C++ Primer 第十三章 13.4 拷贝控制示例 Message类+Folder类

Message类 + Folder类 

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

class Folder;
class Message
{
	friend class Folder;
	friend ostream& operator<<(ostream&, const Message&);
	friend void swap(Message&, Message&);
public:
	explicit Message(const string& s = string()) :contents(s), Folders(set<Folder*>()) {}
	Message(const Message&);
	Message& operator=(const Message&);
	~Message();
	// 这两个才是一般情况下使用的成员函数 保存/移除
	void save(Folder&);
	void remove(Folder&);
private:
	string contents;
	set<Folder*> Folders;
	// 拷贝成员,析构函数需要用的工具函数
	void add_to_Folders(const Message&);
	void remove_from_Folders();                // 双向删除
	// used by Folder class to add self to this Message's set of Folder's
	void addFloder(Folder* f) { Folders.insert(f); }
	void removeFolder(Folder* f) { Folders.erase(f); }
};

class Folder
{
	friend void swap(Message&, Message&);
	friend Message;
public:
	Folder() = default;
	Folder(const Folder&);
	~Folder();
	Folder& operator=(const Folder&);
	void save(Message& m) { Msgs.insert(&m); m.addFloder(this); }
	void remove(Message& m) { Msgs.erase(&m); m.removeFolder(this); }
private:
	set<Message*> Msgs;
	// 拷贝成员,以及析构函数所需要的工具函数
	void add_to_Messages(const Folder&);
	void remove_from_Msgs();            //双向删除,不同于Message的
	// 
	void addMsg(Message* pm) { Msgs.insert(pm); }
	void removeMsg(Message* pm) { Msgs.erase(pm); }
};

void Folder::add_to_Messages(const Folder& f)
{
	for (auto& i : f.Msgs)
		i->addFloder(this);
}

void Folder::remove_from_Msgs()
{
	while (!Msgs.empty())
		(*Msgs.begin())->remove(*this);
}

Folder::Folder(const Folder& f):Msgs(f.Msgs)
{
	add_to_Messages(f);
}

Folder::~Folder()
{
	remove_from_Msgs();
}

Folder& Folder::operator=(const Folder& f)
{
	remove_from_Msgs();
	Msgs = f.Msgs;
	add_to_Messages(f);
	return *this;
}



//``````````````````````````````````````````````````````````
void Message::save(Folder& f)
{
	Folders.insert(&f);
	f.addMsg(this);
}

void Message::remove(Folder& f)
{
	Folders.erase(&f);
	f.removeMsg(this);
}

void Message::add_to_Folders(const Message& m)
{
	for (auto& i : m.Folders)
		i->addMsg(this);  // i是Folder*
}

void Message::remove_from_Folders()
{
	for (auto& i : Folders)
		i->removeMsg(this);
	Folders.clear();
}

Message::Message(const Message& m):Folders(m.Folders),contents(m.contents)
{
	add_to_Folders(m);
}

Message::~Message()
{
	remove_from_Folders();
}

Message& Message::operator=(const Message& m)
{
	remove_from_Folders();
	Folders = m.Folders;
	contents = m.contents;
	add_to_Folders(m);
	return *this;
}



ostream& operator<<(ostream& os, const Message& m)
{
	os << m.contents;
	return os;
}

void swap(Message& lhs, Message& rhs)
{
	using std::swap;
	cout << "???????????" << endl;
	for (auto& i : lhs.Folders)
		i->removeMsg(&lhs);
	for (auto& i : rhs.Folders)
		i->removeMsg(&rhs);
	swap(lhs.contents, rhs.contents);
	swap(lhs.Folders, rhs.Folders);
	for (auto& i : lhs.Folders)
		i->addMsg(&lhs);
	for (auto& i : rhs.Folders)
		i->addMsg(&rhs);
}




int main()
{
	Message m1("111");
	Message m2("222");
	Message m3("333");
	Message m4("444");
	Folder f1;
	Folder f2;
	m1.save(f1);
	m2.save(f1);
	m3.save(f2);
	m4.save(f2);

	m1 = m3;
	cout << &m2 << endl;
	cout << &m4 << endl;
	swap(m2, m4);
	cout << &m2 << endl;
	cout << &m4 << endl;
	return 0;
}

真他妈的快吐了,这个b东西。起初13.4的初衷只是为了举出一个例子:即资源管理并不是一个类需要定义自己的拷贝控制成员的唯一原因。而Message和Folder类就是一个例子,这个类如果仅考虑拷贝构造,以及赋值运算符的本质工作是完全可以的,但是这两个类需要互相进行薄记工作,即Folder中保存着若干Message,就类似于信息以及信息列表。所以当一条信息销毁时,对应的信息列表也应该删除对这个信息的记录,即Folder中的set<Message*>应该删除对应的Message*。

两个类的组成非常相似,如Message类 其中的private成员中有两个函数是用来辅助自己的拷贝成员及析构函数的工作的,即:add_to_Folders 辅助拷贝构造函数和拷贝赋值运算符。remove_from_Folders 辅助析构函数和拷贝赋值运算符。如旧,拷贝赋值运算符结合了析构和拷贝构造的任务。

而另外两个私有成员函数是为了辅助另一个类的一些成员函数完成工作的。

对于swap函数有一种错误的写法

void swap(Message& lhs, Message& rhs)
{
    using std::swap;
	lhs.remove_from_Folders();
	rhs.remove_from_Folders();
	lhs.add_to_Folders(rhs);
	rhs.add_to_Folders(lhs);
	swap(lhs.contents, rhs.contents);
	swap(lhs.Folders, rhs.Folders);
}

错误的原因是remove函数是双向删除的,即当lhs和rhs执行完remove之后,它们的Folders中并不存储着原来的Folder*了。而正确的做法就是利用Folder中的两个私有成员函数来实现。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值