为什么用户定义的移动构造函数禁用隐含拷贝构造函数?为什么用户定义的移动构造函数禁用隐含拷贝构造函数?

2019-06-14 08:55发布

虽然我读升压/ 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

什么是评论“生成的拷贝构造函数,析构函数除了在C ++ 11,移动精细禁用隐式副本”这里的意思? 我们将永远写拷贝构造函数自己,防止在C ++ 11这种情况呢?

Answer 1:

我upvoted ildjarn的答案,因为我发现它既准确又幽默。 :-)

因为我假设,因为为什么标准说这样OP可能想知道这个问题的称号,我提供一个备用的答案。

背景

C ++已经隐含生成的拷贝成员,因为如果它没有,它会被仍然诞生于1985年已经因为它是如此不符合C.而在这种情况下,我们不会有今天这样的谈话,因为C ++就不会存在。

话虽这么说,隐式生成副本成员是类似于一个“魔鬼交易”。 C ++已经不能生下来就没有他们。 但他们是在他们默默实例的显著数量产生不正确的代码邪恶。 在C ++委员会不傻,他们知道这一点。

C ++ 11

现在++已经诞生,并已演变成一个成功的大人是C,该委员会将只是爱说:我们没有做隐式生成副本的成员了。 他们是太危险了。 如果你想要一个隐式生成副本的会员,您有权选择在该决定(而不是选择退出的话)。 然而考虑到现有的C ++代码,如果这样做的目的是将打破量,这将是无异于自杀。 有一个巨大的向后兼容性的关注那是相当有道理的。

因此,该委员会达成了妥协的位置:如果你声明的举动成员(其中传统的C ++代码不能做的),那么我们将假设默认复印成员,很可能做错事。 请选择(用=default ),如果你想他们。 或者自己写他们。 否则,它们被隐式删除。 我们最新的,只有移动类型世界经验表明,这种预设立场实际上是相当普遍所期望的(例如unique_ptrofstreamfuture ,等等)。 而选择加入的费用其实是相当小= default

期待

该委员会很想甚至说:如果你写一个析构函数,很可能隐含的副本成员是不正确的,所以我们将其删除。 这是C ++ 98/03“的三个规则”。 然而,即使这会破坏大量的代码。 然而该委员会表示,C ++ 11,如果你提供一个用户声明的析构函数,复制成员的隐代已经过时了 。 这意味着,此功能可以在未来的标准被删除。 而且现在任何一天你的编译器可能开始在此情况下(标准不能指定警告)发出“警告不推荐使用”。

结论

所以事先警告:C ++已经长大了,成熟了几十年。 这意味着,你父亲的C ++可能需要迁移到处理您的孩子的C ++。 这是一个缓慢的,渐进的过程,这样你就不会扔了你的手,只是端口到另一种语言。 但的变化,即使慢。



Answer 2:

因为C ++标准是这样说的 - §12.8/ 7:

如果类定义不明确声明拷贝构造函数,一个是隐式声明。 如果类定义声明了一个移动构造函数或移动赋值操作符,隐式声明的拷贝构造函数定义为删除 ; 否则,功能为缺省它被定义。 如果类有一个用户声明的拷贝赋值运算符或用户声明的析构函数后一种情况下已被弃用。 因此,对于类定义

 struct X { X(const X&, int); }; 

一个拷贝构造函数是隐式声明的。 如果用户声明的构造在后面定义为

 X::X(const X& x, int i =0) { /* ... */ } 

那么任何使用X的拷贝构造函数是形成不良的,因为模棱两可的; 没有诊断是必需的。

(重点煤矿。)



文章来源: Why user-defined move-constructor disables the implicit copy-constructor?