在C ++ 11中显式删除成员函数,是否仍然值得从不可复制的基类inheritance?
在C ++ 11中显式删除成员函数,是否仍然值得从不可复制的基类inheritance?
我谈论的是你私下inheritance一个具有私有或删除拷贝构造函数和拷贝分配(例如boost::noncopyable
)的基类的技巧。
在这个问题上提出的优点是否仍然适用于C ++ 11?
我不明白为什么有些人声称在C ++ 11中做一个不可复制的类更容易。
在C ++ 03中:
private: MyClass(const MyClass&) {} MyClass& operator=(const MyClass&) {}
在C ++ 11中:
MyClass(const MyClass&) = delete; MyClass& operator=(const MyClass&) = delete;
编辑:
正如许多人指出的那样,为私有拷贝构造函数和复制赋值运算符提供空主体(即{})是错误的,因为这将允许类本身无误地调用这些运算符。 我首先开始不添加{},但遇到了一些链接器问题,使我添加了一些愚蠢的理由(我不记得的情况下)。 我知道更好知道。 🙂
那么这个:
private: MyClass(const MyClass&) {} MyClass& operator=(const MyClass&) {}
技术上还允许成员和朋友复制MyClass
。 当然,这些types和function在理论上是在你的控制之下,但是这个类还是可以复制的 。 至less用boost::noncopyable
和= delete
, 没有人可以复制这个类。
我不明白为什么有些人声称在C ++ 11中做一个不可复制的类更容易。
与“更容易消化”相比,并不那么“容易”。
考虑一下:
class MyClass { private: MyClass(const MyClass&) {} MyClass& operator=(const MyClass&) {} };
如果你是一个C ++程序员,他阅读了C ++的介绍性文章,但很less涉及惯用的C ++(即: 很多 C ++程序员),这是令人困惑的。 它声明了拷贝构造函数和拷贝赋值操作符,但是它们是空的。 那为什么要申报呢? 是的,他们是private
,但只会提出更多的问题:为什么让他们私密?
要理解为什么这样做会阻止复制,你必须认识到,通过声明它们是私人的,你可以让非成员/朋友不能复制它。 这对新手来说并不明显。 当他们试图复制它们时,也不会得到错误信息。
现在,将其与C ++ 11版本进行比较:
class MyClass { public: MyClass(const MyClass&) = delete; MyClass& operator=(const MyClass&) = delete; };
需要了解的是,这个类不能被复制? 没有什么比理解什么= delete
语法的手段。 任何解释C ++ 11语法规则的书都会告诉你具体做什么。 这个代码的效果对于没有经验的C ++用户来说是显而易见的。
这个成语的好处在于它成了一个成语,因为它是确切地expression你的意思的最明显,最明显的方式。
即使boost::noncopyable
需要更多的思考。 是的,它被称为“不可复制”,所以它是自我logging。 但是,如果你以前从来没有见过,这就提出了问题。 你为什么从某些不可复制的东西中获得? 为什么我的错误消息谈论boost::noncopyable
的复制构造函数? 等等,再次,理解这个习语需要更多的精力。
第一件事,就像我之前指出的那样,你有这个成语是错误的,你宣布为私人的,并没有定义 :
class noncopyable { noncopyable( noncopyable const & ); noncopyable& operator=( noncopyable const & ); };
如果operator=
的返回types可以基本上是任何东西。 在这一点上,如果你读了一个头文件中的代码,那实际上是什么意思? 它只能被朋友复制,否则不能复制? 请注意,如果您提供的定义与您的示例中相同,则说明我只能在类中和朋友之间 进行复制,而不能将其转换为我无法复制的定义 。 但是在头文件中缺less一个定义并不是无处不在的定义的同义词,因为它可以在cpp文件中定义。
这是从一个名为noncopyable的typesinheritance的地方明确表示,其目的是为了避免副本,就像你手动编写上面的代码一样,你应该在行中注释一个意思是禁用副本。
C ++ 11并没有改变任何这一点,它只是使代码中的文档显式。 在你声明拷贝构造函数被删除的同一行中,你被logging为你想完全禁用它。
作为最后一条评论,C ++ 11中的function不仅仅是能够使用更less的代码或更好的代码编写非复制代码,而是禁止编译器生成您不想生成的代码。 这只是该function的一个用途。
除了别人提出的观点之外…
有一个你没有定义的私有拷贝构造函数和拷贝赋值操作符可以防止任何人拷贝。 但是,如果成员函数或朋友函数试图进行复制,他们将收到链接时错误。 如果他们试图在明确删除这些函数的地方这样做,他们将收到一个编译时错误。
我总是让我的错误尽快发生。 使运行时错误发生在错误点而不是稍后(所以当你改变variables而不是当你读它时会发生错误)。 将所有运行时错误都变成链接时错误,所以代码从来没有机会出错。 将所有链接时间错误编译为编译时错误,以加快开发速度并获得稍微有用的错误消息。
它更具可读性,并允许编译器提供更好的错误。
“删除”对于读者来说更加清楚,特别是如果他们正在浏览整个课程。 同样,编译器可以告诉你,你试图复制一个不可复制的types,而不是给你一个通用的“尝试访问私有成员”的错误。
但是,真的,这只是一个便利的function。
这里的人build议你声明成员函数而不定义它们。 我想指出,这样的做法是不便携的。 一些编译器/链接器要求,如果你声明了一个成员函数,那么你也必须定义它,即使它没有被使用。 如果你只使用VC ++,GCC,那么你可以避开这个,但是如果你想写真正的可移植代码,那么其他一些编译器(例如Green Hills)将会失败。