8

3 つのコンストラクターを持つこのクラスを検討してください。

class Circle {

public:
 Circle(int r) {
      _radius = r;
 }

Circle(const Circle& c){
    _radius = c.radius();
    cout << endl << "Copy constructor with lvalue reference. Radius: " << _radius;
}

Circle(Circle&& c){
    _radius = c.radius();
    cout << endl << "Copy constructor with rvalue reference. Radius:" << _radius;
}

int radius() const {
    return _radius;
}

private:
    int _radius;
};

int main() {
     Circle c1(2);
     Circle c2(c1);
     cout << endl << c2.radius(); 
     Circle c3(Circle(4));
     cout << endl << c3.radius(); 
     return 0;
 }

「g++ -std=c++0x」でコンパイル。出力は次のとおりです。

Copy constructor with lvalue reference. Radius: 2
2
4

わかった。最初の 2 つのケースの適切なコンストラクターが呼び出されます。しかし、3 番目のケース、つまり Circle c3(Circle(4)) の場合、3 番目のコンストラクター (右辺値参照付きのコピー コンストラクター) が呼び出されることを期待しますが、そうではありません。c3が適切にインスタンス化されているため、明らかにいくつかのコンストラクターが呼び出されますが、コンパイラーが明示的に提供されたコンストラクターを使用しない理由がわかりません。ここで何か不足していますか?

4

3 に答える 3

14

コンパイラがコードに対して賢すぎるため、ムーブ コンストラクタは呼び出されません ;)

 Circle c1(2);

intこれは、変換コンストラクターを使用してオブジェクトを構築するだけです。

 Circle c2(c1);

これはコピー操作です。c1は左辺値なので、コピーを引き起こします。

 Circle c3(Circle(4));

ここで、コンパイラは、基本的にオブジェクトを 2 回構築するように指示していることを認識します。そのため、オブジェクト コンストラクターの 1 つを省略します。これは、このインスタンスでは C++ 仕様によって許可されています。

コンパイラが構造を省略できなかった場合、コンパイラは移動を実行します。また、コンパイラがそれを省略できない場合は、破棄してください。

なので、動きがありません。

于 2012-04-29T17:56:02.697 に答える
7

コンストラクター引数の内容が移動され、通常、これはオペランドの状態を変更する操作であるため、右辺値参照を取得するには、非 const である必要があります (ただし、特定のケースではありません)。

Circle(Circle&& c){ }

また、ここでコピーの省略が見られます。

Circle c3(Circle(4));

そのため、移動コンストラクターは呼び出されません。これは、発生する場合と発生しない場合がある標準的なコンパイラの最適化です。このようなを構築する場合Circle:

Circle c3(std::move(c1));

次に、move コンストラクターを呼び出します。

于 2012-04-29T17:28:36.197 に答える