32

なぜC++コンパイラは、自動生成されたコピーコンストラクタまたは代入演算子よりも自動生成された移動コンストラクタに多くの制限があるのですか?

自動生成された移動コンストラクターは、ユーザーが何も定義していない場合にのみ生成されます(つまり、コンストラクター、コピー、代入、デストラクタなど)。

コピーコンストラクターまたは代入演算子は、ユーザーがコピーコンストラクターまたは代入演算子をそれぞれ定義していない場合にのみ生成されます。

なぜ違いがあるのだろうか。

4

3 に答える 3

15

ここでは、下位互換性が大きな役割を果たしていると思います。ユーザーが「三つのルール」機能(コピー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ます。

デフォルトのムーブコンストラクター定義を妨げるムーブ代入演算子について:ムーブ代入演算子がデフォルト以外のことを行う場合、デフォルトのムーブコンストラクターを使用するのはおそらく間違っているでしょう。これは、実際の「三つのルール」/「三つのルール」にすぎません。

于 2013-03-26T10:28:40.003 に答える
10

私の知る限り、これは下位互換性のためです。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());
}
于 2013-03-26T10:28:02.473 に答える
9

C ++が作成されたとき、デフォルトのコンストラクター、コピーコンストラクター、代入演算子、およびデストラクタが自動的に生成されることが決定されました(提供されていない場合)。なんで ?C ++コンパイラは(ほとんどの)Cコードを同じセマンティクスでコンパイルできるはずなので、それがCでのstruct動作方法です。

ただし、後で、ユーザーがカスタムデストラクタを作成するときは常に、カスタムのコピーコンストラクタ/代入演算子も作成する必要があることに気付きました。これはビッグスリーのルールとして知られています。後から考えると、生成されたコピーコンストラクタ/代入演算子/デストラクタは、3つのうちユーザーが提供したものがない場合にのみ生成され、多くのバグを検出するのに役立つと指定できたことがわかります。 ..そしてCとの下位互換性を維持します。

したがって、C ++ 11が登場したとき、今回は正しく行われることが決定されました。新しいmove-constructorとmove-assignment-operatorは、ユーザーが何もしていないことが明らかな場合にのみ自動的に生成されます。クラスで特別」。移動/コピー/破棄の動作を再定義することとして定義されている「特別な」もの。

人々が何か特別なことをしているが、それでも「自動生成された」特別な方法を望んでいた場合を助けるために、= default砂糖コーティングも追加されました。

残念ながら、下位互換性の理由から、C ++委員会は過去にさかのぼって、コピーの自動生成のルールを変更することができませんでした。標準の次のバージョンへの道を開くために、彼らがそれを非推奨にしたことを望みますが、そうなるとは思えません。ただし、非推奨になりました(たとえば、@ Nevinの厚意により、コピーコンストラクターについては§12.8/ 7を参照してください)。

于 2013-03-26T10:38:03.670 に答える