C++合成的移动构造函数如何受volatile和virtual成员的影响?

use*_*766 10 c++ g++ move-constructor c++11

看下面的代码:

struct node
{

  node();
  //node(const node&);    //#1
  //node(node&&);         //#2

  virtual                 //#3
  ~node ();

  node*
  volatile                //#4
  next;

};

int main()
{

  node m(node());         //#5
  node n=node();          //#6
}
Run Code Online (Sandbox Code Playgroud)

使用gcc-4.6.1编译时会产生以下错误:

g++ -g --std=c++0x   -c -o node.o node.cc
node.cc: In constructor node::node(node&&):
node.cc:3:8: error: expression node::next has side-effects
node.cc: In function int main():
node.cc:18:14: note: synthesized method node::node(node&&) first required here
Run Code Online (Sandbox Code Playgroud)

据我所知,编译器无法在第6行创建默认移动或复制构造函数,如果我取消注释第1行或第2行它编译正常,这很清楚.代码在没有c ++ 0x选项的情况下编译正常,因此错误与默认移动构造函数有关.

但是,节点类中的内容会阻止创建默认移动构造函数吗?如果我评论任何第3行或第4行(即使析构函数非虚拟或使数据成员非易失性)它再次编译,那么这两者的组合是否使它不能编译?

另一个难题,第5行不会导致编译错误,与第6行有什么不同?它是否特定于gcc?还是gcc-4.6.1?

Lig*_*ica 12

[C++11: 12.8/9]: 如果类的定义X没有显式声明一个移动构造函数,那么当且仅当一个类的定义被隐式声明为默认值时

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

[ 注意:当未隐式声明或显式提供移动构造函数时,否则将调用移动构造函数的表达式可能会调用复制构造函数. - 尾注]

这就是你的#3打破综合的原因.

此外,这是很不明朗的是挥发性的类型(包括你node* volatile)是平凡可复制 ; 可以得出结论,它是否是实现定义的,并且在您的情况下,似乎它们不是.

至少,海湾合作委员会让它在第4.7节中非常刻意地停止了工作,提出了向后推进到v4.6.1的建议,我只能假设继续......

所以,鉴于以下内容:

[C++11: 12.8/11]:隐式声明的复制/移动构造函数是其类的内联公共成员.如果具有以下内容,则将类的默认复制/移动构造函数X定义为已删除(8.4.3)X:

  • 用非平凡相应构造的变体构件和X是联合状类,类类型的非静态数据成员M(或其阵列),其不能被复制/移动,因为重载解析(13.3),作为施加到M的相应的构造函数,导致歧义或从默认构造函数中删除或无法访问的函数,
  • 一个B无法复制/移动的直接或虚拟基类,因为重载解析(13.3),应用于B相应的构造函数,会导致歧义或从默认构造函数中删除或无法访问的函数,
  • 任何直接或虚拟基类或具有析构函数的非静态数据成员,该析构函数已从默认构造函数中删除或无法访问,
  • 对于复制构造函数,rvalue引用类型的非静态数据成员,或
  • 对于移动构造函数,一个非静态数据成员或直接或虚拟基类,其类型没有移动构造函数,并且不是简单的可复制.

......这就是为什么你的#4正在打破合成,独立于#3.

至于#5,它实际上并不是一个声明node,而是一个被称为函数的声明m- 这就是为什么它不能再现与构造a相关的症状node(这被称为令人烦恼的解析).