c++ - 消息分配运算符不使用交换

标签 c++ c++11

抱歉,如果标题有点偏离,不知道该用什么。

所以在这本书(C++ 入门第 5 版)中,我正在学习 C++,我遇到了一个问题:

We did not use copy and swap to define the Message assignment operator. Why do you suppose this is so?

我真的不知道,因为即使在分配同一个对象 t 本身时,两者也会产生相同的结果。

两个文件的 main.cpp:

#include <iostream>
#include "Folder.hpp"
#include "Message.hpp"

int main()
{
    Message m("Hello");
    Folder f1, f3;

    m.save(f1);

    Message m2;

    m2 = m;

    m2.save(f3);
    m2.save(f1);

    std::cout << f3.msgs.size() << std::endl;
    std::cout << f1.msgs.size() << std::endl;
    return 0;
}

交换功能:

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);
}

不使用交换

operator=:

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

使用交换进行更改:

消息.hpp Message& operator=(Message);//匹配 def 的新声明

消息.cpp

Message& Message::operator=(Message rhs)
{
    swap(*this, rhs);
    return *this;
}

输出是

2
1

两个版本都符合预期。

我真的不知道不使用 swap 的好处是什么,除了需要做的工作会少一些。

类:

// Message.hpp

#ifndef MESSAGE_HPP
#define MESSAGE_HPP

#include <string>
#include <set>

class Folder;

class Message
{
        friend class Folder;
        friend void swap(Message&, Message&);
        friend std::ostream& print(std::ostream &os, const Message &m);
public:
        explicit Message(const std::string &str = "") : contents(str) { }

        ~Message();

        Message(const Message&);
        Message& operator=(const Message&);

        void save(Folder&);
        void remove(Folder&);
private:
        std::string contents;
        std::set<Folder*> folders;

        void add_to_Folders(const Message&);
        void remove_from_Folders();
};

std::ostream& print(std::ostream &, const Message &);

#endif






// Message.cpp

#include "Message.hpp"
#include "Folder.hpp"

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);
}

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

void Message::remove(Folder &f)
{
        folders.erase(&f);
        f.remMsg(this);
}


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);
        folders.clear();
}


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

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

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


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




// Folder.hpp

#ifndef FOLDER_HPP
#define FOLDER_HPP

#include <ostream>
#include <set>

class Message;

class Folder
{
        friend class Message;
        friend std::ostream& print(std::ostream &, Folder &);
public:
        ~Folder();

        void addMsg(Message *);
        void remMsg(Message *);
private:
        std::set<Message*> msgs;
};

std::ostream& print(std::ostream &, Folder &);

#endif




// Folder.cpp

#include "Folder.hpp"
#include "Message.hpp"

Folder::~Folder()
{
        for (auto &m : msgs)
        {
                m->remove(*this);
        }
}

void Folder::addMsg(Message *m)
{
        msgs.insert(m);
}

void Folder::remMsg(Message *m)
{
        msgs.erase(m);
}

std::ostream& print(std::ostream &os, Folder &f)
{
        for (const auto &m : f.msgs)
        {
                print(os, *m) << std::endl;
        }

        return os;
}

干杯

最佳答案

所以@KeithSmith 发布了一个指向答案的链接,我从那里得到了两个。他们在这里:

Exercise 13.38:

We did not use copy and swap to define the Message assignment operator. Why do you suppose this is so?

@Mooophy copy-and-swap 是一种优雅的方式 动态分配的内存。在 Message 类中,没有分配任何内容 动态地。因此,使用这个习语没有任何意义,而且会成功 由于指向后方的指针,实现起来更加复杂。

@pezy 在这种情况下,swap 函数是特殊的。会清楚二 Message 的文件夹,然后交换成员,并将自己添加到每个 文件夹。但是,Message 赋值运算符只是清除自身,并且 复制成员,并将自己添加到每个文件夹中。 rhs 没有 需要清除并添加到文件夹。所以,如果使用 copy-and-swap define,效率会很低。

基本上 Mooophy 是说 copy-and-swap 是用于动态分配内存的东西,而 Message 类没有动态分配内存。

pezy 说 swap 是不同的,它 swap 将 lhs 和 rhs 添加到每个文件夹,而赋值运算符只添加 lhs,这样效率更高。

只是想感谢 KeithSmith 让我知道链接。

链接:https://github.com/Mooophy/Cpp-Primer

关于c++ - 消息分配运算符不使用交换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31260733/

相关文章:

c++ - 以下使用虚函数的代码有什么问题?

c++ - 更改预处理器符号的值以进行测试

c++ - 在派生类上将 std::make_unique 与自定义删除器一起使用?

c++ - std::array 作为类的模板参数

c++ - 解释 size_t(*)(const std::pair<int, int>&) 是什么意思

c++ - 是否有可以与 GCC 4.9.x 一起使用的 GSL 实现?

c++ - 通过模板-模板参数使用枚举标记对象

c++ - 变量是大小为 1 的数组吗?

c++ - 在 rxcpp 中创建自定义运算符

c++ - 如何获得枚举的基本类型?