なぜC++コンパイラは、自動生成されたコピーコンストラクタまたは代入演算子よりも自動生成された移動コンストラクタに多くの制限があるのですか?
自動生成された移動コンストラクターは、ユーザーが何も定義していない場合にのみ生成されます(つまり、コンストラクター、コピー、代入、デストラクタなど)。
コピーコンストラクターまたは代入演算子は、ユーザーがコピーコンストラクターまたは代入演算子をそれぞれ定義していない場合にのみ生成されます。
なぜ違いがあるのだろうか。
ここでは、下位互換性が大きな役割を果たしていると思います。ユーザーが「三つのルール」機能(コピーctor、コピー割り当てop、dtor)のいずれかを定義する場合、クラスが何らかの内部リソース管理を行うと見なすことができます。移動コンストラクターを暗黙的に定義すると、C ++ 11でコンパイルすると、クラスが突然無効になる可能性があります。
この例を考えてみましょう。
class Res
{
int *data;
public:
Res() : data(new int) {}
Res(const Res &arg) : data(new int(*arg.data)) {}
~Res() { delete data; }
};
これで、このクラスに対してデフォルトの移動コンストラクターが生成された場合、その呼び出しにより、が二重に削除されdata
ます。
デフォルトのムーブコンストラクター定義を妨げるムーブ代入演算子について:ムーブ代入演算子がデフォルト以外のことを行う場合、デフォルトのムーブコンストラクターを使用するのはおそらく間違っているでしょう。これは、実際の「三つのルール」/「三つのルール」にすぎません。
私の知る限り、これは下位互換性のためです。C ++(C ++ 11より前)で記述されたクラスと、C++11が既存のコピーコンストラクターまたは一般的に他のctorと並行してmove-ctorsを自動的に生成し始めたらどうなるかを考えてみてください。そのクラスの作成者が書いたcopy-ctorをバイパスすることで、既存のコードを簡単に壊してしまいます。したがって、「安全な」ケースにのみ適用されるように作成されたmove-ctorを生成するためのルール。
これは、暗黙の移動が行われなければならない理由についてのDave Abrahamsの記事であり、最終的にはC++11の現在のルールにつながりました。
そして、これはそれがどのように失敗するかの例です:
// NOTE: This example assumes an implicitly generated move-ctor
class X
{
private:
std::vector<int> v;
public:
// invariant: v.size() == 5
X() : v(5) {}
~X()
{
std::cout << v[0] << std::endl;
}
};
int main()
{
std::vector<X> y;
// and here is where it would fail:
// X() is an rvalue: copied in C++03, moved in C++0x
// the classes' invariant breaks and the dtor will illegally access v[0].
y.push_back(X());
}
C ++が作成されたとき、デフォルトのコンストラクター、コピーコンストラクター、代入演算子、およびデストラクタが自動的に生成されることが決定されました(提供されていない場合)。なんで ?C ++コンパイラは(ほとんどの)Cコードを同じセマンティクスでコンパイルできるはずなので、それがCでのstruct
動作方法です。
ただし、後で、ユーザーがカスタムデストラクタを作成するときは常に、カスタムのコピーコンストラクタ/代入演算子も作成する必要があることに気付きました。これはビッグスリーのルールとして知られています。後から考えると、生成されたコピーコンストラクタ/代入演算子/デストラクタは、3つのうちユーザーが提供したものがない場合にのみ生成され、多くのバグを検出するのに役立つと指定できたことがわかります。 ..そしてCとの下位互換性を維持します。
したがって、C ++ 11が登場したとき、今回は正しく行われることが決定されました。新しいmove-constructorとmove-assignment-operatorは、ユーザーが何もしていないことが明らかな場合にのみ自動的に生成されます。クラスで特別」。移動/コピー/破棄の動作を再定義することとして定義されている「特別な」もの。
人々が何か特別なことをしているが、それでも「自動生成された」特別な方法を望んでいた場合を助けるために、= default
砂糖コーティングも追加されました。
残念ながら、下位互換性の理由から、C ++委員会は過去にさかのぼって、コピーの自動生成のルールを変更することができませんでした。標準の次のバージョンへの道を開くために、彼らがそれを非推奨にしたことを望みますが、そうなるとは思えません。ただし、非推奨になりました(たとえば、@ Nevinの厚意により、コピーコンストラクターについては§12.8/ 7を参照してください)。