删除默认C ++副本并移动构造函数和赋值运算符的缺点是什么?

时间:2016-02-13 03:28:55

标签: c++ copy-constructor move-constructor

如果有一个类的实例永远不会被复制而且从未移动过,那么删除默认移动和复制构造函数和赋值运算符是否有任何缺点?这确实直接违反规则0,但是还有其他缺点(编译器会生成次优代码,次优数据布局等)吗?

3 个答案:

答案 0 :(得分:2)

是否存在特殊成员函数对数据布局没有影响。好吧,至少达到标准可以保证的程度。也就是说,类是否是标准布局(因此具有明确定义的布局)与其构造函数无关。它只与其成员有关。如果课程不是标准布局......则标准不保证任何内容。

然而,在理论上,没有理由没有特殊的构造函数来影响班级的布局。

显然,标准无法强制实施最佳代码"代。但是,没有任何理由说明所述成员的存在与否会导致为您定义的函数生成更糟糕的代码。

将特殊成员函数声明为已删除应该只会在有人试图调用时导致编译失败。

现在,有一些边缘情况,但这些是用户代码如何使用它们的。也就是说,如果您将对此类的引用传递给某些打算移动它的模板代码。但它可以接受固定类型,但它必须使用较慢的算法(出于某种原因)。它将使用std::is_move_constructible来检测该类型是否可移动并使用较慢的算法。

  

这确实直接违反了规则0

......那又怎样?规则是使用默认语义,除非您的类需要其他语义。 unique_ptr在概念上是一种复制毫无意义的类型,因此它会删除复制操作。如果您的类型在概念上是一种复制和移动没有意义的类型,那么您应该删除这些操作。

注意"毫无意义"意味着它在逻辑上无效,基于您的类型正在做什么。 unique_ptr按照定义,唯一拥有一个对象。复制指针意味着它没有唯一拥有该对象。由于这在逻辑上无效,因此无法复制该类。

如果你的课程在概念上是不动的,那么你应该用C ++使其保持不动。

答案 1 :(得分:1)

  

如果有一个类的实例永远不会复制且从未移动过,

这可能意味着两件事之一:

  1. 实例绝不能被复制或移动,因为这样做会导致诸如浅层复制之类的错误,或者因为从语义角度来看它没有意义。
  2. 实例当前不会发生进行复制或移动。
  3.   

    删除默认移动和复制有什么缺点   构造函数和赋值运算符?

    取决于这两个含义中的哪一个是正确的:

    1. 不。恰恰相反;你应该绝对删除它们以避免意外调用这些功能。
    2. 是。稍后当您的班级客户端代码发生变化并需要复制或移动时,您将不得不撤消它。或者更糟糕的是,客户端程序员可能会实现不必要且容易出错的变通方法,包括指向实例的指针,或者手动复制,首先从第一个实例中提取数据,然后使用提取的数据构建一个新实例(想象一下{{1}的混乱}或std::string无法复制。)

答案 2 :(得分:0)

没有缺点。但也没有任何优势。它完全没有任何成就。编译器只会在需要时生成默认构造函数或运算符。如果他们不需要,他们是否被正式删除没有任何区别。

现在有什么区别,就是当你明确要强制执行一个类实例时,不能复制,分配等等。有一些特殊的类可能无法赋值或移动构造等等,这有很多原因。您始终可以定义适当的构造函数或运算符,并抛出异常。但是,在这种情况下,您会发现某些东西在运行时已经存在。

但是,你不同意它会更好,相反,让编译器在编译时强制执行无移动构造/赋值,而不是运行时?因为如果构造函数/运算符被删除,并且某处出现错误,编译器会立即对你大喊大叫。