C ++:如果我不使用移动,我还需要关注复制控制吗?

时间:2016-09-04 06:03:48

标签: c++ move copy-constructor

复制控件似乎与默认构造函数,复制构造函数,复制赋值运算符,析构函数等相关,是用户编写的复制和复合的复制,加上移动复制/赋值。

听起来很复杂。我发现很难记住合成的内容和时间。

只是想知道,如果我不在构造函数或赋值运算符中使用move,我还需要关注差异吗?

1 个答案:

答案 0 :(得分:3)

在用户代码中,您几乎不需要编写析构函数,因此复制/移动构造函数和赋值运算符。这是因为您将编写启用RAII的对象类。

我们需要编写析构函数的唯一一次是我们是否控制非RAII资源,例如从c样式或原始c ++库导出的文件句柄或数据库连接。

在这种情况下,我们只需将资源包装在unique_ptr(使用自定义删除工具)或shared_ptr(再次使用自定义删除工具)中,我们就完成了。

这给我们留下了两个场景:

  1. 多态接口的基类(不受shared_ptr控制) - 在这种情况下,我们必须编写一个虚拟析构函数,然后根据默认实现实现移动/复制。

  2. 一个可移动的类(因为它拥有unique_ptr,比方说?),我们希望它是可复制的。现在我们被迫实施复制操作并默认移动操作。

  3. 还有一些其他极端情况,例如您的类是否拥有互斥锁,这是不可复制的。但是,如果您的类拥有互斥锁,则可能已经存在设计错误,要求它可以复制。无论如何,到这个时候你应该已经了解了复制/分配/移动规则。

    一些例子:

    struct owns_a_file_movable
    {
        struct file_deleter {
            void operator()(FILE* f) const noexcept {
                fclose(f);
            }
        };
    
        // RAII class now, moveable. Copy would not make sense.
        std::unique_ptr<FILE, file_deleter> file_;
    };
    
    struct owns_a_file_copyable
    {
        struct file_deleter {
            void operator()(FILE* f) const noexcept {
                fclose(f);
            }
        };
    
        // construct from string
        owns_a_file_copyable(std::string fname)
        : path_(std::move(fname))
        , file_(fopen(path_, "r"), file_deleter())
        {
        }
    
        // we want it to be copyable. In our case, a copy will open another
        // instance of the file. so we must store the filename.
    
        owns_a_file_copyable(owns_a_file_copyable const& r)
        : path_(t.path_)
        , file_(fopen(path_, "r"), file_deleter())
        {}
    
        owns_a_file_copyable& operator=(owns_a_file_copyable const& r)
        {
            auto tmp = r;
            std::swap(path_, tmp.path_);   // changed: was r.path_ which was wrong
            std::swap(file_, tmp.file_);
            return *this;
        }
    
        owns_a_file_copyable(owns_a_file_copyable&&) = default;
        owns_a_file_copyable& operator=(owns_a_file_copyable&&) = default;
    
    
        // std::string is fully RAII
        std::string path_;
    
        // RAII class now, moveable
        std::unique_ptr<FILE, file_deleter> file_;
    };
    
    struct how_most_classes_should_be 
    {
        // no destructors, copy operators, assignment or move - it's all 
        // generated for you.
    
        std::string this_;
        std::string that_;
        std::shared_ptr<const OtherThing> shared_other_; // note - shared semantics
        std::function<void()> closure_;   // these are copyable too
    };
    

    对于athos

    什么触发了什么?

    // ordinary constructor
    auto y = owns_a_file_copyable("/users/rhodges/foo.txt");
    
    // copy constructor: owns_a_file_copyable(owns_a_file_copyable const&)
    auto x = y;
    
    // copy assignment: owns_a_file_copyable& operator-(owns_a_file_copyable const&)
    x = y
    
    // move-constructor: owns_a_file_copyable(owns_a_file_copyable &&)
    auto z = std::move(x);
    
    // move-assignment: owns_a_file_copyable& operator-(owns_a_file_copyable &&)
    z = std::move(y);
    
    // also move-constructor
    extern owns_a_file_copyable make_file();
    auto w = make_file();
    
    // this time move-assignment
    w = make_file();