6

特に定数データメンバーを持つクラスのコンテキストで、ムーブコンストラクターまたはムーブ代入演算子が呼び出されるタイミングとかどうかを理解するのにいくつかの問題があります。クラスを検討する

template<typename T> class A {
  const*T const P ;   // constant data member
  explicit A(const*T p) : P(p) { std::cerr<<" ctor: P="<<P<<'\n'; }
  void test() const { std::cerr" test: P="<<P<<'\n'; }
  // move and copy constructors and assignment operators here
};

とテストプログラム

class B {
  int X[100];
  A<B> get_a() const { return A<B>(this); }
};

int main() {
  B b;
  A<B> a = b.get_a();   // which operator/ctor is used for '=' here?
  a.test();
}

その場合、コンパイルの結果は、クラスのムーブコンストラクターとムーブ代入演算子に提供される定義によって異なりますがA<>、コンパイラーによっても異なります。

1 (上記のように)クラスでそれ以上の宣言がない場合A<>、g ++(4.7.0)とicpc(13.0.1)の両方が正常にコンパイルされ(オプション付き-std=c++11)、期待される出力を生成します

ctor: P=0x7fffffffd480
test: P=0x7fffffffd480

2私が宣言した場合

A&A::operator=(A&&) = delete;
A&A::operator=(const A&) = delete;

(これは、initialiser-listで初期化する必要がある定数データメンバーを考慮すると賢明なようです)が、それ以上のctorを提供しない場合、コンパイルはg ++で失敗しますが、icpcでは問題ありません。さらに、次のいずれか(または両方)を定義する場合

A::A(A&&) = default;
A::A(const A&) = default;

両方のコンパイラが満足しています。ただし、g++はこの組み合わせに満足していません

A::A(A&&) = delete;
A::A(const A&) = default;

icpcが幸せな間。

3 2と同じゲームをプレイした場合、それが次のようA::A(A&&) = default;に置き換えられます。

A::A(A&&a) : P(a.P) { std::cerr<<" move ctor: P="<<P<<'\n'; } // never called?

(およびと同等A::A(const A&))、結果は完全に同一です。特に、これらの明示的な移動およびコピーctorからの出力は生成されません。

では、どの演算子がで使用さ=main()ますか?(そして、なぜ最後のテストで出力が生成されないのですか?)

また、定数データメンバーがある場合(メンバーをA<>に置き換えても結果は同じです) 、この操作がここで許可されるのはなぜですか?const*T const P;const T&R

最後に、g ++とicpcの動作が異なる場合、どちらが正しいですか?

4

1 に答える 1

2
A<B> a = b.get_a();

は割り当てではなく、a右辺値からの初期化です。この構文は、C++0xでは失敗するはずです。

  1. 移動コンストラクターが削除され、
  2. 移動コンストラクターが宣言されていますexplicit
  3. コピーコンストラクターが削除され、移動コンストラクターが定義されていません。
  4. ムーブコンストラクターは定義されておらず、同時にムーブ代入が定義または削除されています。

コピー代入演算子の宣言または削除は影響を与えないはずです。

修正:コピーコンストラクター(ユーザー定義のコピー代入演算子が指定されている場合でも合成されます)とは異なり、ユーザー定義のムーブ代入が定義されている場合、コンパイラーはムーブコンストラクターを合成しません。したがって、上記のリストは4で修正する必要があります(これは私が今行っています)。

したがって、私の意見では、

  • 質問の[1]では、両方のコンパイラが正しく動作します。
  • [2] / 1では、gccは正しく動作します(ムーブ代入はムーブコンストラクターの生成を防ぎます)、icpcは間違っています、
  • [2] / 2では、両方のコンパイラが正しいですが、
  • [2] / 3では、moveコンストラクターが明示的に削除されているため、gccは正しいです。icpcが間違っている、
  • [3]は私には謎です。あなたは正しいですか?
于 2012-11-26T13:26:55.000 に答える