1. 程式人生 > >C++Primer第五版 第十三章習題答案(31~40)

C++Primer第五版 第十三章習題答案(31~40)

31:這幾題都是舉例使用動態記憶體管理類,多是程式碼,多寫寫

#include<iostream>  
#include<string>
#include<vector>
#include<algorithm>
using namespace std;

class Hasptr1
{
	friend void swap(Hasptr1&,Hasptr1&);
	friend bool operator<(const Hasptr1& s1,const Hasptr1& s2);
	friend void show(vector<Hasptr1>& vec);
public:
	//建構函式,初始化相關成員
	Hasptr1(const string& s = string()):ps(new string(s)),i(0),use(new size_t(1)){}

	//拷貝建構函式,將引用計數也拷貝過來,並且遞增引用計數
	Hasptr1(const Hasptr1& p):ps(p.ps),i(p.i),use(p.use){++*use;}

	//拷貝賦值運算子
	Hasptr1& operator= (const Hasptr1& p1)
	{
		++*p1.use;//首先遞增右側運算子物件的引用計數
		if (--*use == 0)//遞減本物件的引用計數,若沒有其他使用者,則釋放本物件的成員
		{
			delete ps;
			delete use;
		}
		ps = p1.ps;//進行拷貝
		use = p1.use;
		i = p1.i;
		return *this;
	}

	//解構函式
	~Hasptr1()
	{
		if (*use == 0)//引用計數變為0,說明已經沒有物件再需要這塊記憶體,進行釋放記憶體操作
		{
			delete ps;
			delete use;
		}
	}
private:
	//定義為指標,是我們想將該string物件儲存在動態記憶體中
	string *ps;
	size_t *use;//將計數器的引用儲存
	int i;
};

inline void swap(Hasptr1& a,Hasptr1& b)
{
	using std::swap;
	swap(a.ps,b.ps);
	std::swap(a.i,b.i);
	cout<<"123";
}

bool operator< (const Hasptr1& s1,const Hasptr1& s2)
{
	cout<<"定義的 Operator< 被呼叫"<<endl;
	return *s1.ps < *s2.ps;
}

void show(vector<Hasptr1>& vec)
{
	vector<Hasptr1>::iterator it1 = vec.begin();
	for (it1; it1 != vec.end(); ++it1)
	{
		cout<<*(it1->ps)<<endl;
	}
}
int main(int argc, char**argv)  
{
	vector<Hasptr1> vec1;
	Hasptr1 a("l");
	Hasptr1 b("llll");
	Hasptr1 c("lll");
	vec1.push_back(a);
	vec1.push_back(b);
	vec1.push_back(c);
	vector<Hasptr1>::iterator it1 = vec1.begin();
	sort(vec1.begin(),vec1.end());
	show(vec1);
	return 0;
}  

32:類指標的類版本,使用編譯器自帶的swap()函式即可完成目標操作,並不需要自定義一個swap以交換指標所指向的值,所以並不會提升效果

33:我們的目的是對傳入的folder進行修改,傳值的方式會使得我們修改的是其副本,const修飾符使得我們不能對其進行修改。所以都不行

34:

#ifndef MESSAGE_H//防止標頭檔案重複包含
#define MESSAGE_H

#include <string>
#include <set>
using namespace std;
class Message
{
	friend class Folder;
public:
	Message(const Message& m):contents(m.contents),folders(m.folders)//拷貝建構函式
	{
		add_to_Folders(m);//拷貝時,將新建立的message的指標新增到每個包含的folder中
	}

	Message& operator=(const Message& mm)//拷貝賦值運算子
	{
		remove_from_Folders();//刪除自身
		contents = mm.contents;
		folders = mm.folders;
		add_to_Folders(mm);//將本message傳入folder中
		return *this
	}

	Message(const string &str = ""):contents(str){}//建構函式
	void swap(Message& m1,Message& m2)
	{
		using std::swap;
		//先將每個message從其folders中刪除
		for(auto f : m1.folders)
		{
			f->remMsg(this);//所有包含此message的folder進行刪除操作
		}
		for(auto f : m2.folders)
		{
			f->remMsg(this);//所有包含此message的folder進行刪除操作
		}
		swap(m1.folders,m2.folders);
		swap(m1.contents,m2.contents);
		for (auto f : m1.folders)
		{
			f->addMsg(this);//再進行新增操作
		}
		for (auto f : m2.folders)
		{
			f->addMsg(this);
		}
	}

	~Message()//解構函式
	{
		remove_from_Folders();
	}

	void save(Folder&);
	void remove(Folder&);//對Folder類的操作函式
private:
	string contents;//資訊內容
	set<Folder*> folders;//包含本message的folder序列
	void add_to_Folders(const Message&);
	void remove_from_Folders();//從folders中刪除本message
};

void Message::save(Folder& f)
{
	folders.insert(&f);//將給定folder加入到我們的folders中
	f.addMsg(this);//將本message新增到給定folder中
}

void Message::remove(Folder& f)
{
	folders.erase(&f);//將給定folder在我們的folders中刪除
	f.remMsg(this);//將本message在給定folder中刪除
}

void Message::add_to_Folders(const Message& m)
{
	for (auto f : m.folders)
	{
		f->addMsg(this);
	}
}
void Message::remove_from_Folders()
{
	for (auto f : folders)
	{
		f->remMsg(this);//所有包含此message的folder進行刪除操作
	}
}

#endif MESSAGE_H


35:若使用合成的拷貝控制成員,則folders不會更新,所包含資訊錯亂

36:

class Folder
{
public:
	Folder();
	~Folder();
	Folder& operator=(const Folder&);
	Folder(const Folder&);

	void addMsg(Message *m3)//上面需要使用this作為引數,所以這裡需要用指標
	{
		messages.insert(m3);
	}
	void remMsg(Message *m4)
	{
		messages.erase(m4);
	}
private:
	set<Message*> messages;//儲存Message的指標
};


37:見34題程式碼

38:當涉及到動態分配記憶體時,拷貝並交換是一個完成該功能的精簡的方式. ,但是在Message類中,並未涉及到動態分配記憶體,這種方法並不會產生任何益處,同時還會因為很多指標操作讓程式變得更復雜難難以實現

39:

void StrVec::alloc_n_move(size_t new_cap)
{
	auto newdata = alloc.allocate(new_cap);
	auto dest = newdata;
	auto elem = elements;
	for (size_t i = 0; i != size(); ++i)
		alloc.construct(dest++, std::move(*elem++));
	free();
	elements = newdata;
	first_free = dest;
	cap = elements + new_cap;
}

void StrVec::reallocate()
{
	auto newcapacity = size() ? 2 * size() : 1;
	alloc_n_move(newcapacity);
}

void StrVec::reserve(size_t new_cap)
{
	if (new_cap <= capacity()) return;
	alloc_n_move(new_cap);
}

void StrVec::resize(size_t count)
{
	resize(count, std::string());
}

void StrVec::resize(size_t count, const std::string& s)
{
	if (count > size()) {
		if (count > capacity()) reserve(count * 2);
		for (size_t i = size(); i != count; ++i)
			alloc.construct(first_free++, s);
	}
	else if (count < size()) {
		while (first_free != elements + count) alloc.destroy(--first_free);
	}
}


40:主要為三個指標進行初始化,並將成員進行賦值

StrVec(initializer_list<string>lst){ 
    auto newdata=alloc_n_copy(lst.begin(),lst.end());  
    elements=newdata.first;  
    first_free=cap=newdata.second;  
}