10

次のコードを見てください。

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
}

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

私が理解しているように、コンパイラは 6 行目でデフォルトの移動コンストラクターまたはコピー コンストラクターを作成できません。1 行目または 2 行目のいずれかのコメントを外すと、正常にコンパイルされます。コードは c++0x オプションなしで正常にコンパイルされるため、エラーはデフォルトのムーブ コンストラクターに関連しています。

しかし、ノード クラスの何がデフォルトの移動コンストラクターの作成を妨げているのでしょうか? 行 #3 または #4 のいずれかをコメントすると (つまり、デストラクタを非仮想にするか、データ メンバーを非揮発性にする)、再びコンパイルされますが、これら 2 つの組み合わせによってコンパイルされないのでしょうか?

もう 1 つのパズル、5 行目ではコンパイル エラーが発生しませんが、6 行目との違いは何ですか? それはすべてgccに固有ですか?または gcc-4.6.1?

4

1 に答える 1

12

[C++11: 12.8/9]: Xクラスの定義でmoveコンストラクターが明示的に宣言されていない場合、クラスの定義は、次の場合にのみ、デフォルトとして暗黙的に宣言されます。

  • Xユーザーが宣言したコピーコンストラクターはありません。
  • Xユーザーが宣言したコピー代入演算子がありません。
  • Xユーザーが宣言したムーブ代入演算子はありません。
  • Xユーザーが宣言したデストラクタがなく
  • 移動コンストラクターは、削除済みとして暗黙的に定義されません。

[注: moveコンストラクターが暗黙的に宣言されていないか、明示的に指定されていない場合、moveコンストラクターを呼び出す式は、代わりにcopyコンストラクターを呼び出す可能性があります。—エンドノート]

それがあなたの#3が統合を破っている理由です。

さらに、揮発性タイプ(あなたを含む)が自明にコピー可能であることは明らかではありません; それらが実装であるかどうかは実装によって定義されていると結論付けることができますが、あなたの場合はそうではないようです。node* volatile

少なくとも、GCCはv4.7でかなり意図的に動作を停止させ、v4.6.1にバックポートする提案をしました。

したがって、次のようになります。

[C++11: 12.8/11]:暗黙的に宣言されたコピー/移動コンストラクターは、そのクラスのインラインパブリックメンバーです。クラスのデフォルトのコピー/移動コンストラクターは、次の場合にX削除済み(8.4.3)として定義されXます。

  • 自明ではない対応するコンストラクターを持つバリアントメンバーでありX、ユニオンのようなクラスであり、クラスタイプ(またはその配列)の非静的データメンバーであり、 'sMに適用されるオーバーロード解決(13.3)のためにコピー/移動できません。M対応するコンストラクターは、デフォルトのコンストラクターから削除されるかアクセスできないあいまいさまたは関数になります。
  • の対応するコンストラクターに適用されるオーバーロード解決(13.3)により、デフォルトのコンストラクターから削除またはアクセスできないあいまいさまたは関数が発生するBため、コピー/移動できない直接または仮想の基本クラス。B
  • デフォルトのコンストラクタから削除された、またはアクセスできないデストラクタを持つタイプの直接または仮想の基本クラスまたは非静的データメンバー。
  • コピーコンストラクターの場合、右辺値参照型の非静的データメンバー、または
  • 移動コンストラクターの場合、非静的データメンバー、または移動コンストラクターを持たず、簡単にコピーできない型の直接または仮想基本クラス。

...それが、#3とは関係なく、#4も合成を破っている理由です。

#5に関しては、これは実際にはaの宣言ではnodeなく、と呼ばれる関数の宣言です。そのため、amの構築に関連する症状を再現していませんnode(これは最も厄介な解析として知られています)。

于 2012-11-15T22:35:33.137 に答える