2

したがって、最初にコーディングします。

#include <iostream>
#include <utility>

struct X{
    int i;
    void transform(){}
    X() :i(0){std::cout<<"default\n";}
    X(const X& src): i(src.i){std::cout<<"copy\n";}
    X(X&& msrc) :i(msrc.i){msrc.i=0;std::cout<<"move\n";}
};

X getTransform(const X& src){
    X tx(src);
    tx.transform();
    return tx;
}

int main(){

    X x1;// default
    X x2(x1); // copy
    X x3{std::move(X{})}; // default then move
    X x41(getTransform(x2)); // copy in function ,then what?
    X x42(std::move(getTransform(x2))); // copy in funciton, then move
    X x51( (X()) );//default, then move? or copy?
      // extra() for the most vexing problem
    X x52(std::move(X())); //default then move
    std::cout<<&x41<<"\t"<<&x51<<std::endl;
}

次に、C++11 機能をオンにして cygwin + gcc 4.8.2 から出力します。

default
copy
default
move
copy
copy
move
default
default
move
0x22aa70        0x22aa50

私がよく理解していないのは、x41 と x51 の行です。x41 の場合、関数呼び出しから返された一時的に移動コンストラクタまたはコピーを呼び出す必要がありますか? x51についても同じ質問です。
2 番目の質問は、出力を見ると、x41 と x51 の構成では、定義されたコンストラクターが呼び出されませんでしたが、オブジェクトはメモリ内に常駐しているため、明らかに作成されているということです。これはどうやってできるの?

4

3 に答える 3

6

名前のないオブジェクトは、自然に&&よりもよく一致します。 そうしないと、ムーブ セマンティクスが機能しません。const&

これで、デフォルト/コピー/ムーブ コンストラクターへの呼び出しが少なくなり、単純に期待できるようになりました。これは、観察可能な動作に関係なく、コピーの省略を許可する特別なルールがあるためです (それ以外の場合は最適化によって保持する必要があります)。

12.8 オブジェクトのコピーと移動 § 31

特定の基準が満たされると、オブジェクトのコピー/移動コンストラクターおよび/またはデストラクタに副作用がある場合でも、実装はクラス オブジェクトのコピー/移動構築を省略できます。このような場合、実装は、省略されたコピー/移動操作のソースとターゲットを、同じオブジェクトを参照する 2 つの異なる方法として扱い、そのオブジェクトの破棄は、2 つのオブジェクトが削除されていた時間のうちの遅い方の時点で発生します。最適化なしで破棄されます。
それでも、関数から返され、同じ型のオブジェクトを初期化するために直接使用される場合、その移動は省略されます。
—クラスの戻り値の型を持つ関数の return ステートメントで、式が関数の戻り値の型と同じ cv 非修飾型を持つ非揮発性自動オブジェクト (関数または catch 句のパラメーター以外) の名前である場合、自動オブジェクトを関数の戻り値に直接構築することにより、コピー/移動操作を省略できます。
参照にバインドされていない一時クラス オブジェクトの場合(12.2) が同じ cv 非修飾型のクラス オブジェクトにコピー/移動される場合、コピー/移動操作は、一時オブジェクトを省略されたコピー/移動のターゲットに直接構築することによって省略できます。
- [... 例外処理用にあと 2 つ]

だから、あなたのリストを見てみましょう:

X x1;// default
// That's right
X x2(x1); // copy
// Dito
X x3{std::move(X{})}; // default then move
// Yes. Sometimes it does not pay to call `std::move`
X x41(getTransform(x2)); // copy in function ,then what?
// Copy in function, copy to output, move-construction to x41.
// RVO applies => no copy to output, and no dtor call for auto variable in function
// Copy ellision applies => no move-construction nor dtor of temporary in main
// So, only one time copy-ctor left
X x42(std::move(getTransform(x2))); // copy in funciton, then move
// `std::`move` is bad again
X x51( (X()) );//default, then move? or copy? // extra() for the most vexing problem
// Copy-elision applies: default+move+dtor of temporary
// will be optimized to just default
X x52(std::move(X())); //default then move
// And again `std::`move` is a pessimization

使用すると一時的なバインドが回避される可能性があると思いました。つまり、移動を省略できる可能性がありますstatic_castが、そのような運はありません。

于 2014-06-11T21:02:23.380 に答える
1

標準§ 12.8 [クラスオブジェクトのコピーと移動]によると

31特定の基準が満たされている場合、コピー/移動操作用に選択されたコンストラクターおよび/またはオブジェクトのデストラクタに副作用がある場合でも、実装はクラス オブジェクトのコピー/移動構築を省略できます。このような場合、実装は、省略されたコピー/移動操作のソースとターゲットを、同じオブジェクトを参照する 2 つの異なる方法として扱い、そのオブジェクトの破棄は、2 つのオブジェクトが削除された後の時点で発生します。124 copy elision と呼ばれるこのコピー/移動操作の省略は 、次の状況で許可されます (複数のコピーを排除するために組み合わせることができます)。

  • クラスの戻り値の型を持つ関数の return ステートメントで、式が関数の戻り値の型と同じ cvunqualified 型を持つ不揮発性自動オブジェクト (関数または catch 節パラメーター以外) の名前である場合、コピー/move 操作は、自動オブジェクトを関数の戻り値に直接構築することで省略できます。

  • 参照 (12.2) にバインドされていない一時クラス オブジェクトが 同じ cv 非修飾型のクラス オブジェクトにコピー/移動される場合、一時オブジェクトをターゲットに直接構築することにより、コピー/移動操作を省略できます。省略されたコピー/移動の

したがって、両方の場合 (つまり、x41それぞれx51) で、コピー省略の最適化効果が発生しています。

于 2014-06-11T21:10:53.227 に答える
1

単純に戻り値の最適化が始まっていると思います。 on の関数内でコピーを作成するX tx(src);と、このローカル変数がメインに返されます。意味的にはコピーですが、実際にはコピー操作は省略されています。

他の人が言ったように、移動も省略できます。

于 2014-06-11T20:50:47.933 に答える