ama*_*jxq 38 c++ boost copy-constructor rvalue-reference c++11
当我正在阅读boost/shared_ptr.hpp时,我看到了这段代码:
// generated copy constructor, destructor are fine...
#if defined( BOOST_HAS_RVALUE_REFS )
// ... except in C++0x, move disables the implicit copy
shared_ptr( shared_ptr const & r ): px( r.px ), pn( r.pn ) // never throws
{
}
#endif
Run Code Online (Sandbox Code Playgroud)
注释"生成复制构造函数,析构函数是否正常,除了在C++ 11中,移动禁用隐式副本"是什么意思?我们是否总是自己编写副本来防止C++ 11中出现这种情况?
How*_*ant 97
我赞成了ildjarn的回答,因为我发现它既准确又幽默.:-)
我提供了另一个答案,因为我假设因为问题的标题,OP可能想知道为什么标准这样说.
背景
C++隐式生成了复制成员,因为如果它没有,它将在1985年出生,因为它与C 是如此不兼容.在这种情况下,我们今天不会进行这种对话,因为C++不存在.
话虽如此,隐含生成的副本成员类似于"与恶魔打交道".如果没有它们,C++就不可能诞生.但它们是邪恶的,因为它们在大量实例中默默地生成错误的代码.C++委员会并不愚蠢,他们知道这一点.
C++ 11
现在C++诞生了,并且已经发展成为一个成功的成年人,委员会只想说:我们不再做隐式生成的复制成员了.他们太危险了.如果您想要一个隐式生成的副本成员,您必须选择加入该决定(而不是选择退出它).但是考虑到如果这样做会破坏现有C++代码的数量,那就等于自杀了.有一个巨大的向后兼容性问题是非常合理的.
所以委员会达成了妥协的立场:如果你宣布移动成员(遗留的C++代码不能做),那么我们将假设默认的副本成员可能做错了.选择加入(含=default),如果你想他们.或者自己写.否则会隐式删除它们.我们最新的,只有移动类型世界经验表明,这种预设立场实际上是相当普遍所期望的(例如unique_ptr,ofstream,future等).选择费用实际上相当小= default.
期待
委员会甚至愿意说:如果你编写了一个析构函数,那么隐式复制成员可能是不正确的,所以我们将删除它们.这是C++ 98/03"三个规则".然而,即便这样也会破坏很多代码.但是,委员会在C++ 11中说过,如果提供用户声明的析构函数,则不推荐使用隐式生成的复制成员.这意味着可以在将来的标准中删除此功能.现在,在这种情况下,您的编译器可能会在任何一天开始发出"已弃用的警告"(标准不能指定警告).
结论
因此要预先警告:C++已经成长并成熟了几十年.这意味着你父亲的C++可能需要迁移才能处理你孩子的C++.这是一个缓慢,渐进的过程,所以你不要举手,只是移植到另一种语言.但这是变化,即使很慢.
ild*_*arn 24
因为C++标准如此说 - §12.8/ 7:
如果类定义没有显式声明复制构造函数,则会隐式声明一个.如果类定义声明了移动构造函数或移动赋值运算符,则隐式声明的复制构造函数被定义为已删除 ; 否则,它被定义为默认.如果类具有用户声明的复制赋值运算符或用户声明的析构函数,则不推荐使用后一种情况.因此,对于类的定义
Run Code Online (Sandbox Code Playgroud)struct X { X(const X&, int); };隐式声明了复制构造函数.如果用户声明的构造函数稍后定义为
Run Code Online (Sandbox Code Playgroud)X::X(const X& x, int i =0) { /* ... */ }然后,由于模糊性,任何使用X的复制构造函数都是不正确的; 无需诊断.
(强调我的.)