C ++规则5复制和移动(构造函数和赋值)告诫:复制或移动

时间:2015-04-06 04:48:53

标签: c++ move copy-constructor

我正在编写符合c ++ 11 +标准的类,现在是我实施5规则的时候了。

  1. Destructor
  2. Copy Constructor
  3. Move Constructor
  4. Copy Assignment Operator
  5. Move Assignment Operator

  6. 我有一个关于复制/移动构造函数/赋值的问题。我的理解是,复制构造函数/赋值应该复制(浅,深?)类。如果您的类具有唯一成员(例如unique_ptr),则可以预见两种情况。

    • 制作对象的深层副本

      在我的情况下,我不确定如何制作一份深层副本(见下面的代码)。

    • 将对象移动到另一个类

      在我看来,在复制构造函数中移动指针会对用户产生意想不到的副作用,因为他们期望复制而不是移动,并且复制的原始对象将不再起作用。

      制作副本也可能有问题,但在我的情况下,curl对象可能包含敏感信息,如Cookie或密码?


    为具有这些约束的类创建复制和移动构造函数/赋值的实际方法是什么?要深层复制,移动,还是不显式和隐式定义复制构造函数(does the delete keyword do this)?


    // client.h
    #pragma once
    
    #include <Poco/URI.h>
    #include <curl/curl.h>
    
    class client
    {
    public:
        typedef Poco::URI uri_type;
        // Constructor
        client(const uri_type & auth);
        // Destructor
        virtual ~client();
        // Copy constructor
        client(const client & other);
        // Move constructor
        client(client && other);
        // Copy assignment
        client & operator=(const client & other);
        // Move assignment operator
        client & operator=(client && other);
    
    private:
        uri_type auth_;
        // ... other variables (both unique and copyable) ommitted for simplicity.
        std::unique_ptr<CURL, void(*)(CURL*)> ptr_curl_;
    };
    

    // client.cpp
    #include <memory>
    #include <Poco/URI.h>
    #include <curl/curl.h>
    
    #include "client.h"
    
    // Constructor
    client::client(const uri_type & auth)
    : auth_(auth)
    , ptr_curl_(curl_easy_init(), curl_easy_cleanup)
    {
        curl_global_init(CURL_GLOBAL_DEFAULT);
    }
    
    // Destructor
    client::~client()
    {
        curl_global_cleanup();
    }
    
    // Copy constructor
    client::client(const client & other)
    {
        // ... deep copy? move?
        // how would you deep copy a unique_ptr<CURL>?
    }
    
    // Move constructor
    client::client(client && other)
    {
        std::swap(*this, other);
    }
    
    // Copy assignment
    client & client::operator=(const client & other)
    {
        // Cant get this to work by making the copy happen in the parameter.
        client temp(other);
        std::swap(*this, temp);
        return *this;
    }
    
    // Move assignment operator
    client & client::operator=(client && other)
    {
        return *this;
    }
    

2 个答案:

答案 0 :(得分:3)

如名称所示,复制构造函数/赋值运算符应始终COPY而不移动其成员,其中复制通常表示深层复制。

记住:默认情况下,c ++中的所有对象都应该具有值语义,即它们的行为应该像int

此外,帖子中的术语表明您将唯一对象(单例)与unique_ptr指向的对象混淆。大多数不可复制的对象都是处理程序(如unique_ptr处理堆上的对象),在这种情况下,您可以复制它们处理的任何内容。如果那是不可能的,那么很可能,实现对象的复制构造函数是没有意义的。

如果您的对象拥有对唯一资源的拥有引用(项目中只能有一个实例),那么第一个问题是:它可以共享吗? - &GT;使用shared_ptr。如果不是 - &gt;不要复制。 如果对象拥有对唯一ressource(原始指针或引用)的非拥有引用,则复制引用。在这两种情况下,请注意您现在有两个共享其状态的对象,即使在非多线程应用程序中也可能存在危险。

答案 1 :(得分:1)

对于某些类型,拥有复制构​​造函数是不合适的。这包括大多数在语义上包含不可复制类型的类型。 (不计算unique_ptr,计算CURL实例)

如果libcurl具有“duplicate_handle”类型的函数,那么复制构造函数应该使用它来初始化副本中的unique_ptr。否则,您应该删除您的复制构造函数,并仅执行move。