特に定数データメンバーを持つクラスのコンテキストで、ムーブコンストラクターまたはムーブ代入演算子が呼び出されるタイミングとかどうかを理解するのにいくつかの問題があります。クラスを検討する
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の動作が異なる場合、どちらが正しいですか?