13.4 拷贝控制示例

来源:互联网 发布:淘宝网商城女包包 编辑:程序博客网 时间:2024/05/22 05:08

13.33:为什么Message的成员save和remove的参数时一个Folder &?为什么我们不将参数定义为Folder或是const Folder &?

成员内部调用的函数需要改变Folder中的元素,Folder或是const Folder &都无法做到。

13.34:编写本节所描述的Message。

class Folder;class Message {friend void swap(Message &, Message &);string contents;set<Folder*> folders;void add_to_Folders(const Message &);void remove_form_Folders();public:explicit Message(const string &str = "") :contents(str) {}Message(const Message &);~Message();Message & operator = (const Message &);void save(Folder &);void remove(Folder &);};void swap(Message &, Message &);//声明//容器set内部会构造指针的副本Message::Message(const Message &msg) :contents(msg.contents), folders(msg.folders) {add_to_Folders(msg);}Message::~Message() {remove_form_Folders();}Message &  Message::operator = (const Message &msg) {remove_form_Folders();contents = msg.contents;folders = msg.folders;//容器set内部会构造指针的副本add_to_Folders(msg);//将本消息添加到指向msg的所有Folder中return *this;}void Message::save(Folder &fd) {folders.insert(&fd);fd.addMsg(this);}void Message::remove(Folder &fd) {folders.erase(&fd);fd.remMsg(this);}void Message::add_to_Folders(const Message &msg) {for (auto f : msg.folders)f->addMsg(this);}void Message::remove_form_Folders() {for (auto f : folders)f->remMsg(this);}void swap(Message &lhs, Message &rhs) {using std::swap;for (auto f : lhs.folders)f->remMsg(&lhs);for (auto f : rhs.folders)f->remMsg(&rhs);swap(lhs.folders, rhs.folders);swap(lhs.contents, rhs.contents);for (auto f : lhs.folders)f->addMsg(&lhs);for (auto f : rhs.folders)f->addMsg(&rhs);}

13.35:如果Message使用合成版本的拷贝控制成员,将会发生什么?

当拷贝一个Message时,副本的指针将不会出现在任何一个Folder中(尽管它包含了其所在Folder的指针set)。更严重的,当某Message析构后,其所在Folder中任然保留了该Message的指针,该指针是无效的!

13.36:设计并实现对应的Folder类。此类应该保存一个指向Folder中包含的Message的set。

class Folder {set<Message*> messages;public:void addMsg(Message *const pMsg) { messages.insert(pMsg); }void remMsg(Message *const pMsg) { messages.erase(pMsg); }};


13.37:为Message类添加成员,实现向folders添加或删除一个给定的Folder*。这两个成员类似Folder类的addMsg和remMsg操作。

class Message {//其余成员void addFolder(Folder *const fd) { folders.insert(fd); }void remFolder(Folder *const fd) { folders.erase(fd); }};

13.38:我们并未使用拷贝并交换方式来设计Message的赋值运算符。你认为原因是什么?

如459页所示,使用swap设计的赋值运算符采用的是值传递的方式传递参数,会引起Message中整个set的拷贝;更重要的是,尽管只是值传递,但是swap仍然会更新到运算符右侧的Message的folders,这显然不是我们所希望的。
原创粉丝点击