在c++ 11中禁用复制类的最简洁的方法

Most concise way to disable copying class in C++11

本文关键字:简洁 方法 复制 c++      更新时间:2023-10-16

当存在用户定义的析构函数时,我有一个问题处理自c++ 11以来默认生成的复制构造函数和复制赋值操作符。

对于大多数足够简单的类,默认生成的构造函数、操作符和析构函数就可以了。考虑以下声明析构函数的原因:

  1. 使普通析构函数在基类中为虚函数:

    // header
    class Base1 { public: virtual ~Base1() = default; };
    class Base2 { public: virtual ~Base2(); };
    // source
    Base2::~Base2() = default;
    

    在这些情况下,编译器会生成所有4个复制和移动特殊方法吗?如果是,那么我认为这很好,没有必要使Base1Base2复杂化。

  2. 在析构函数中打印调试信息:

    // header
    class D { public: ~D(); };
    // source
    D::~D() {
    #ifdef DEBUG_THIS
        std::cout << "D was destructed." << std::endl;
    #endif
    }
    

    我相信在这种情况下会生成复制构造函数和赋值操作符;但是move构造函数和赋值操作符不能。我想避免使用过时的默认生成并禁用D的复制。我还想避免用4个deleted声明淹没D。禁用一个复制构造函数是否足够?这是一种好风格吗?

对于c++ 11,一个干净的方法是遵循boost中使用的模式(参见这里)

创建一个基类,删除复制构造函数和复制赋值,并继承它:

class non_copyable
{
protected:
    non_copyable() = default;
    ~non_copyable() = default;
    non_copyable(non_copyable const &) = delete;
    void operator=(non_copyable const &x) = delete;
};
class MyClass: public non_copyable
{
...
}

删除复制构造函数和复制赋值操作符是禁用复制的最简单、最清晰的方法:

class X
{
    X(X const &) = delete;
    void operator=(X const &x) = delete;
};

我不明白你在问题体中的虚析构函数是什么意思。这听起来像是你在要求一种方法,使你的代码占用更少的源代码字符,但也更神秘的任何人看它。

如果删除的函数列表让您感到困扰,我猜您可以将它们隐藏在宏后面。

 #define NON_COPYABLE_NOR_MOVABLE(T)  
      T(T const &) = delete; 
      void operator=(T const &t) = delete; 
      T(T &&) = delete;
  1. 当显式默认了析构函数时,只生成复制构造函数和复制赋值操作符。即便如此,他们这一代也不受待见。因此,为了拥有虚析构函数和所有默认方法,应该这样写:

    struct Base
    {
        Base()=default;
        virtual ~Base() = default;
        Base(const Base&)=default;
        Base& operator=(const Base&)=default;
        Base(Base&&)=default;
        Base& operator=(Base&&)=default;
    };
    

    我肯定会使用一个以上的宏Base类。

  2. 如果析构函数是用户定义的,仍然会生成2个特殊的方法。有以下方法可以禁用已弃用的生成复制构造函数和复制赋值操作符:

    • delete移动构造函数或移动赋值操作符(不太清楚,但很短):

      Base(Base&&)=delete; // shorter than deleting assignment operator
      
    • delete 复制构造函数和复制赋值操作符:

      Base(const Base&)=delete;
      Base& operator=(const Base&)=delete;
      

    请注意,如果需要,必须显式声明默认构造函数,例如Base()=default;

    宏或继承特殊类也可以用于此目的,但我个人更喜欢删除移动构造函数来实现我自己的宏或基类。当使用Qtboost时,我更喜欢分别继承Q_DISABLE_COPY(Base)boost::noncopyable,因为它们已经实现,广为人知且可识别。

http://accu.org/index.php/journals/1896 -这些问题的详细解释和基本原理。

你可以这样做(这是Caffe使用的:一个快速开放的深度学习框架):

// Disable the copy and assignment operator for a class.
#define DISABLE_COPY_AND_ASSIGN(classname) 
private:
  classname(const classname&);
  classname& operator=(const classname&)

使用例子:

class CNoCopyable{
    public:
        CNoCopyable(int i):m_d(i){}
    private:
        int m_d;
        // add this line(pass class name)
        DISABLE_COPY_AND_ASSIGN(CNoCopyable);
};