c++ - 为什么用户定义的移动构造函数会禁用隐式复制构造函数?

标签 c++ boost c++11 copy-constructor rvalue-reference

在阅读 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

这里的注释“生成的复制构造函数,析构函数很好,除了在 C++11 中,移动禁用隐式复制”是什么意思?在 C++11 中我们是否应该总是自己编写复制 ctor 来防止这种情况?

最佳答案

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

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

背景

C++ 已经隐式生成了复制成员,因为如果它没有,它会在 1985 年死产,因为它与 C 不兼容。在那种情况下,我们不会今天有这个话题,因为 C++ 不存在。

话虽如此,隐式生成的拷贝成员类似于“与魔鬼打交道”。没有它们,C++ 就不可能诞生。但它们是邪恶的,因为它们在大量实例中默默地生成错误代码。 C++ 委员会并不愚蠢,他们知道这一点。

C++11

既然 C++ 已经诞生,并且已经发展成为一个成功的成年人,委员会只想说:我们不再做隐式生成的复制成员了。他们太危险了。如果您想要一个隐式生成的拷贝成员,您必须选择加入该决定(而不是选择退出)。但是考虑到如果这样做会破坏现有 C++ 代码的数量,那无异于自杀。 巨大的向后兼容性问题是完全合理的。

因此委员会达成了妥协的立场:如果您声明 move 成员(旧版 C++ 代码无法做到这一点),那么我们将假设默认的 copy 成员可能会做错事。如果需要,可选择加入(使用 =default)。或者自己写。否则,它们将被隐式删除。迄今为止,我们在只移动类型的世界中的经验表明,这个默认位置实际上是非常常见的(例如 unique_ptrofstreamfuture 等)。并且使用 = default 选择加入的费用实际上非常小。

展望 future

委员会甚至想说:如果您编写了析构函数,则隐式复制成员很可能不正确,因此我们将删除它们。这是 C++98/03 “三法则”。然而,即使这样也会破坏很多代码。然而,委员会在 C++11 中表示,如果您提供用户声明的析构函数,则复制成员的隐式生成已弃用。这意味着可以在未来的标准中删除此功能。并且现在任何一天你的编译器都可能在这种情况下开始发出“不推荐使用的警告”(标准不能指定警告)。

结论

因此请注意:C++ 已经成长和成熟了几十年。这意味着您父亲的 C++ 可能需要迁移以处理您 child 的 C++。这是一个缓慢而渐进的过程,因此您不会举手而只是移植到另一种语言。但它正在发生变化,即使速度很慢。

关于c++ - 为什么用户定义的移动构造函数会禁用隐式复制构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11255027/

相关文章:

c++ - 仍然存在与 boost::mutex 的竞争条件

C++ bitset 问题

c++ - 使用 boost::array 中的 std::string::assign 与 std::array 的不兼容性

c++ - Qt 智能指针相当于 Boost::shared_ptr ?

c++ - 符合标准的 C assert() 可以多次评估其参数吗?

c++ - 为什么使用常量表达式作为模板参数?

c++ - 显式运算符 << 选择 'wrong' 重载

c++ - 如何在大型 C++ 程序中为所有 double 类型的数字设置小数精度

c++ - 强制 cmake 使用旧的 bo​​ost 库

c++ - 有没有办法保证析构函数的相对顺序?