【问题标题】:Can a move constructor be implicit?移动构造函数可以是隐式的吗?
【发布时间】:2012-10-31 22:34:48
【问题描述】:

考虑以下类:

class A
{
public:
   std::string field_a;
   std::string field_b;
}

现在考虑以下复制结构:

A a1(a2);

尽管缺少显式复制构造函数,复制构造仍将充分复制 A,因为 std::string 的复制构造函数将由编译器生成的隐式复制构造函数调用。

我想知道的是,移动构造是否也是如此?

编辑:测试here 表明:

A a2(std::move(a1));

实际上会导致复制构造,除非特定的移动构造函数:

A( A && other ) : a(std::move(other.a)) {}

已定义。

编辑编辑 我联系了 Stephan T Lavavej,问他为什么 VC 2012 似乎没有遵循 12.8 草案中关于隐式移动构造函数生成的规定。他好心解释:

与其说是错误,不如说是“尚未实现的功能”。目前风投 实现了我所说的右值引用 v2.0,其中 move ctors/assigns 永远不会隐式生成,也不会影响 复制ctors/assigns的隐式生成。 C++11 指定右值 参考 v3.0,这是您正在查看的规则。

【问题讨论】:

标签: c++ visual-c++ c++11 visual-studio-2012 move-semantics


【解决方案1】:

是的,来自 C++11 草案,12.8:

如果类 X 的定义没有显式声明移动构造函数,则会隐式声明 默认当且仅当

  • X 没有用户声明的复制构造函数,
  • X 没有用户声明的复制赋值运算符,
  • X 没有用户声明的移动赋值运算符,
  • X 没有用户声明的析构函数,并且
  • 移动构造函数不会被隐式定义为已删除。

后面会详细说明最后一个条件:

隐式声明的复制/移动构造函数是其类的内联公共成员。如果 X 具有以下属性,则类 X 的默认复制/移动构造函数被定义为已删除 (8.4.3):

  • 具有非平凡对应构造函数的变体成员,并且 X 是类联合类,
  • 类类型 M(或其数组)的非静态数据成员,无法复制/移动,因为 应用于 M 的相应构造函数的重载决议 (13.3) 会导致歧义或 从默认构造函数中删除或无法访问的函数,
  • 由于重载决议 (13.3) 而无法复制/移动的直接或虚拟基类 B,如 应用于 B 的相应构造函数,导致歧义或函数被删除或 无法从默认构造函数访问,
  • 具有已删除析构函数的类型的任何直接或虚拟基类或非静态数据成员 或无法从默认构造函数访问,
  • 对于复制构造函数,右值引用类型的非静态数据成员,或
  • 对于移动构造函数,非静态数据成员或直接或虚拟基类,其类型没有移动构造函数且不可轻易复制。

简单地说,移动构造函数将在以下情况下被隐式声明:

  1. 该类没有用户声明的任何其他特殊成员函数。
  2. 移动构造函数可以通过移动其所有成员和基数来实现。

你的班级显然符合这些条件。

【讨论】:

  • 那么看看我附加的编辑,为什么我没有得到一个隐式移动构造?
  • Nitpick:来自我的草稿(2011-02-28),这是“12.8”部分。
  • ideone.com/1tBOpe 似乎表明,对于 g++,需要显式移动构造函数。
  • @Benj:可能是编译器错误?或者代码可能与您复制的不完全相同。我试过了,它适用于 GCC 4.7.2。然而,在 ideone 中,与 GCC 4.5 相同的代码工作。
  • @OlafDietsche:我的也是,一个错字!谢谢!
【解决方案2】:

如果可以并且没有用户定义的复制构造函数,编译器会合成一个移动构造函数。如果有复制构造函数,则不合成移动构造函数的限制旨在避免破坏现有代码。当然,所有成员都需要是可移动的。确切的规则涉及更多。

【讨论】:

  • 除非专门删除自动生成的构造函数,否则不会一直存在复制构造函数吗?所以换句话说,std::string 的移动构造将不会发生,除非定义了显式移动构造函数。
  • @Benj:我想,我会在合适的地方加入“用户定义”。合成的复制构造函数不算在内。
  • 那么为什么在这个程序中似乎需要一个显式的移动构造函数:ideone.com/1tBOpe(注意如果移动构造函数被注释掉了)
  • @Benj:这个程序应该显示什么?它不会显示字符串是否移动:两个对象可以连接或断开连接。特别是,从字符串中移出的内容可以保持在相当随机的状态。此外,在我尝试使用(gcc 和 clang)的编译器上,无论是否定义了移动构造函数,它们都会产生相同的输出。您也许可以使用带仪表的可移动字体来观察动作。
猜你喜欢
  • 2020-09-07
  • 2012-11-09
  • 1970-01-01
  • 2020-02-09
  • 2015-06-30
  • 1970-01-01
  • 2020-08-27
  • 2012-01-07
  • 2013-08-27
相关资源
最近更新 更多