使用C++ 11中显式删除的成员函数,是否仍然值得从不可复制的基类继承?

Emi*_*ier 58 c++ noncopyable c++11

使用C++ 11中显式删除的成员函数,是否仍然值得从不可复制的基类继承?

我在谈论私有继承基类的技巧,该基类具有私有或删除的复制构造函数和复制赋值(例如boost::noncopyable).

这个问题提出的优势是否仍适用于C++ 11?


我不明白为什么有些人声称在C++ 11中使类不可复制更容易.

在C++ 03中:

private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}
Run Code Online (Sandbox Code Playgroud)

在C++ 11中:

MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
Run Code Online (Sandbox Code Playgroud)

编辑:

正如许多人所指出的那样,为私有拷贝构造函数和拷贝赋值运算符提供空体(即{})是错误的,因为这将允许类本身调用那些运算符而没有任何错误.我首先开始没有添加{},但遇到了一些链接器问题,这些问题让我添加{}有些愚蠢的原因(我不记得这些情况).我知道更清楚.:-)

Nic*_*las 75

好吧,这个:

private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}
Run Code Online (Sandbox Code Playgroud)

技术上仍然允许MyClass成员和朋友复制.当然,这些类型和功能在理论上是在你的控制之下,但是这个类仍然是可复制的.至少boost::noncopyable= delete,没有人可以复制课程.


我不明白为什么有些人声称在C++ 11中使类不可复制更容易.

它不像"更易消化"那么"容易".

考虑一下:

class MyClass
{
private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}
};
Run Code Online (Sandbox Code Playgroud)

如果你是一个C++程序员,他已经阅读了关于C++的介绍性文章,但很少接触惯用的C++(即:许多 C++程序员),这就是......令人困惑.它声明了复制构造函数和复制赋值运算符,但它们是空的.那么为什么要宣布它们呢?是的,他们是private,但这只会引发更多问题:为什么要将它们私有化?

要理解为什么这会阻止复制,你必须意识到,通过将它们声明为私有,你可以使它成为非成员/朋友无法复制它.这对新手来说并不是很明显.它们尝试复制时也不会出现错误消息.

现在,将它与C++ 11版本进行比较:

class MyClass
{
public:
    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

理解这个类无法复制需要什么?没有什么比理解= delete语法的含义更重要了.任何解释C++ 11语法规则的书都会告诉你它究竟是做什么的.对于没有经验的C++用户来说,这段代码的效果是显而易见的.

这个成语的优点在于它成为一种习语,因为它是说出你的意思的最明确,最明显的方式.

甚至boost::noncopyable需要更多的思考.是的,它被称为"不可复制",因此它是自我记录的.但如果你以前从未见过它,它就会引发一些问题.你为什么从无法复制的东西中衍生出来?为什么我的错误消息会谈论boost::noncopyable复制构造函数?等等.再次理解成语需要更多的心理努力.

  • +1我喜欢你如何说明`= delete`不一定更容易编写,但更容易*读*. (12认同)

Dav*_*eas 24

第一件事是,正如我之前的其他人指出的那样,你的成语是错误的,你宣称是私有的并且没有定义:

class noncopyable {
   noncopyable( noncopyable const & );
   noncopyable& operator=( noncopyable const & );
};
Run Code Online (Sandbox Code Playgroud)

哪里的返回类型operator=基本上都可以.此时,如果您在标题中读取该代码,它实际上意味着什么?它只能被朋友复制或者无法复制?请注意,如果您在示例中提供了一个定义,则表明我只能在类中和朋友中复制,缺少定义将其转换为无法复制的定义.但由于缺乏在头的定义不是一个缺乏定义的代名词无处不在,因为它可以在cpp文件中定义.

这是继承自一个名为noncopyable的类型的地方,它明确表示目的是避免复制,就像你手动编写上面的代码一样,你应该在意图禁用副本的行中记录注释.

C++ 11不会改变任何这一点,它只是使代码中的文档显式化.在您将复制构造函数声明为已删除的同一行中,您会记录您希望它完全禁用.

作为最后的评论,C++ 11中的功能不仅仅是能够用更少的代码或更好的代码编写不可复制的,而是禁止编译器生成您不希望生成的代码.这只是该功能的一种用途.

  • **你提出了一个非常重要的观点**:空的私有实现不会阻止你自己错误地复制对象!这个成语不是*来提供空的私人定义.习语只提供*声明*. (3认同)

Dav*_*one 10

除了其他人提出的要点......

拥有您未定义的私有拷贝构造函数和拷贝赋值运算符会阻止任何人进行拷贝.但是,如果成员函数或朋友函数尝试复制,则会收到链接时错误.如果他们尝试在显式删除这些函数的情况下执行此操作,则会收到编译时错误.

我总是让我的错误尽快发生.使运行时错误发生在错误点而不是稍后(因此,当您更改变量而不是在读取变量时,会发生错误).将所有运行时错误转换为链接时错误,以便代码永远不会出错.将所有链接时错误转换为编译时错误,以加快开发速度并获得稍微有用的错误消息.


Col*_*nee 5

它更具可读性,允许编译器提供更好的错误.

"删除"对于读者来说更加清晰,特别是如果他们在课堂上略读的话.同样,编译器可以告诉您,您正在尝试复制不可复制的类型,而不是为您提供通用的"尝试访问私有成员"错误.

但实际上,这只是一个便利功能.