2016-09-06 2 views
3

stdテンプレートライブラリの本を読んでいて、STLコンテナの章に記載されている以下の詳細と混同しています。 どうやら、それはSTDをspecfies :: VECTOR運用と効果std :: vectorまたは任意のオブジェクトの移動コンストラクタを呼び出すタイミングをC++コンパイラが決定する方法

Operation      Effect 

vector<Elem> c(c2) | Copy constructor; creates a new vector as a copy of c2 (all elements are copied) 
vector<Elem> c = c2 | Copy constructor; creates a new vector as a copy of c2 (all elements are copied) 
vector<Elem> c(rv) | Move constructor; creates a new vector, taking the contents of the rvalue rv (since C++11) 
vector<Elem> c = rv | Move constructor; creates a new vector, taking the contents of the rvalue rv (since C++11) 

どうやら、excatly彼らは呼ばれている移動とコピーコンストラクタの両方の構文に違いは、ありませんか?コピーコンストラクタの

おかげ

+4

明示的な 'std :: move'呼び出しがなければ、それはコンパイラによって異なります。仕様にはいくつかのルールがあるかもしれませんが、AFAIKはほとんどがコンパイラに任されています。 r値を渡すと、コンパイラーはスマートになり、移動コンストラクターを呼び出します。 –

+0

また、変数を初期化するとき、 '='を使用しても、割り当てを後で行うときと同じ方法ではないことにも注意してください。例: 'int a = 5;'は*初期化*ですが、 'int a; a = 5; 'は*割り当て*です。 –

+0

@JoachimPileborg私の混乱は、コンパイラが移動コンストラクタまたはコピーコンストラクタを呼び出すことを決定するときです。呼び出しは両方とも同じです – LearningCpp

答えて

-1

構文: クラス名(のconstクラス名&)移動コンストラクタの

構文: クラス名(クラス名& &)

呼び出しが一緒に同じに見えますが、その宣言があります異なる。

参考:

std::vector<int> f(); 

関数によって返された値が右辺値です:

http://en.cppreference.com/w/cpp/language/copy_constructor http://en.cppreference.com/w/cpp/language/move_constructor

+0

ええ、使用法が同じであれば、コンパイラー呼び出しの移動コンストラクターになります。どのようにコンパイラーが任意のアイデアを決定しますか? – LearningCpp

+0

移動コンストラクタを呼び出すには、次のようにします:T a(std :: move(b))。これは明白なケースです。暗黙的な場合は、詳細を参照してください。 – Khoa

+0

@LearningCpp - JoachimPileborgの最初のコメントを見てください: 'std :: vector v1; std :: vector v2(v1); '、' v2'は 'v1'をもう一度使うことができるのでコピーコンストラクタと呼ばれます。 'std :: vector v1;を書くと、 std :: vector v2(std :: move(v1)); '、' v2'は 'std :: move()'を使って移動コンストラクタと呼ばれます。 'v1'をもう一度。 – max66

4

みましょうあなたは値によってベクトルを返す関数fを持っていると言います。

そして、あなたはあなたのベクトルを初期化するために、この関数を呼び出すしたいと言うことができます:fによって返されたベクトルは、もはや使用されることはありません

std::vector<int> v = f(); 

今コンパイラは知っているが、それは一時的なですオブジェクトであるため、一時オブジェクトは一度に破棄されるだけであるため、この一時オブジェクトをコピーするのは意味がありません。したがって、コンパイラは代わりに移動コンストラクタを呼び出すことにします。

+0

ああ、そう、それはすべてr値の存在に依存していますか? iamが間違っていれば私を訂正してください。 – LearningCpp

+0

@LearningCppはい。 '&&'は* rvalueの参照を意味します。 –

+1

しかし、もう一度、これはおそらく移動されず、むしろRVOが来ます:( –

2

どうやら、確かに、これは本当です、移動、コピーコンストラクタ

両方の構文に違いはありません。これはstd::vectorに固有のものではありませんが、一般的にすべてのタイプに適用されます。コピーと移動によるコピー初期化はまったく同じ構文です。コピー割り当てにも同じことが言えます。

違いは、引数式の型に由来します。引数が非const r値の場合、オーバーロード解決によって移動コンストラクタ/割り当てが優先されます。それ以外の場合は、move-constructorは適用されないため、コピーコンストラクタが使用されます。

私がc2

RVおよびc2はオブジェクトではないと思われるようにRVはちょうど構築されたオブジェクトであると仮定します。彼らは明らかに表現のプレースホルダーです。この本はそれについてはっきりしているかもしれません(おそらく、抜粋は文脈から外れているかもしれません)。

2

おそらく、理解を深めるために構文をセマンティクスから切り離す必要があります。このコードを考えてみましょう。

struct A { 
    A(int i) {} 
    A(const std::string& s) {} 
}; 

ここで、次の行が見つかると、どのコンストラクタが呼び出されますか?

A a(x); 

あなたはxは、int型またはSTD ::文字列を持っているかどうかわからないので、あなたはそれを伝えることはできません。あなたの例ではあまり変わっていませんが、移動セマンティクスでは、引数がrvalueかどうかをコンパイラが検査します。そのようなAクラスが(移動)コンストラクタのオーバーロードを提供し、xが値の参照である場合、それが望ましいでしょう。

4

それは理にかなっていると呼ばれているムーブコンストラクタは、元のオブジェクトが望ましくないれ、(おそらく)変更されているように、オブジェクトを移動させて意味をなさないその後それを使用して、すなわち、それを呼び出す:

std::vector<int> a = { 1 }; 
std::vector<int> b = a; //Let's say this called move constructor 
int value = a[0]; //value is possibly not 1, the value may have changed due to the move 

ので、その場合には、コピーコンストラクタが呼び出されます。それは右辺値、または一時的な値に割り当てられているため

std::vector<int> a = { 1, 2 }; 
std::vector<int> b = a; //Copy constructor 

しかし、ここでそれは、移動のコンストラクタを呼び出すん:

void foo(std::vector<int>) {} 
foo({ 1, 2 }); //move constructor 

ベクトル{ 1, 2 }は一時的なベクターで、変更されている場合は気にしますか? fooが終了したらすぐにベクターが破壊されるので、あなたは決して知りません。一時的なベクトルをコピーするだけでは時間が無駄になります。

関連する問題