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

ved*_*edg 19 c++ destructor c++11

自从C++ 11默认生成复制构造函数和复制赋值运算符(存在用户定义的析构函数)时,我遇到了一个问题.

对于大多数足够简单的类,默认生成的构造函数,运算符和析构函数都可以.请考虑以下原因来声明析构函数:

  1. 在基类中创建虚拟析构函数虚拟:

    // header
    class Base1 { public: virtual ~Base1() = default; };
    class Base2 { public: virtual ~Base2(); };
    // source
    Base2::~Base2() = default;
    
    Run Code Online (Sandbox Code Playgroud)

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

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

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

    我相信在这种情况下会生成复制构造函数和赋值运算符; 但移动构造函数和赋值运算符不会.我想避免使用已弃用的默认生成和禁用复制D.我还想避免D4次deleted声明泛滥.是否仅禁用一个复制构造函数?这是一种好风格吗?

qua*_*dev 17

使用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
{
...
}
Run Code Online (Sandbox Code Playgroud)


M.M*_*M.M 12

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

class X
{
    X(X const &) = delete;
    void operator=(X const &x) = delete;
};
Run Code Online (Sandbox Code Playgroud)

我不会在问题正文中跟随你所说的虚拟析构函数.这听起来像是在寻找一种方法来让你的代码占用较少的源代码字符,但对于任何看到它的人来说也更加神秘.

如果删除的功能列表困扰你,你可以将它隐藏在宏后面,我猜.

 #define NON_COPYABLE_NOR_MOVABLE(T) \ 
      T(T const &) = delete; \
      void operator=(T const &t) = delete; \
      T(T &&) = delete;
Run Code Online (Sandbox Code Playgroud)

  • 如果您没有使用支持`= delete`语法的编译器,我强烈建议您使用该宏.它不仅更具可读性(有助于一目了然地查看代码),而且它也是*可搜索的*,其方式是私有函数列表不是. (2认同)

ved*_*edg 7

  1. 当析构函数被明确默认时,将只生成复制构造函数和复制赋值运算符.即便如此,他们这一代人也被弃用了.因此,为了拥有虚拟析构函数和所有默认方法,应该编写以下内容:

    struct Base
    {
        Base()=default;
        virtual ~Base() = default;
        Base(const Base&)=default;
        Base& operator=(const Base&)=default;
        Base(Base&&)=default;
        Base& operator=(Base&&)=default;
    };
    
    Run Code Online (Sandbox Code Playgroud)

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

  2. 在用户定义析构函数的情况下,仍然会生成2种特殊方法.有以下方法可以禁用已弃用的生成复制构造函数和复制赋值运算符:

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

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

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