2015-01-11 14 views
18
  • この例のデフォルトコピーとstd :: moveの違いは何ですか?
  • moveの後には、新しいオブジェクトと古いオブジェクトの間に依存関係がありますか?
int main() { 

    int a = 100; 
    std::cout<<&a<<std::endl; 

    auto a_copy = a;     // deduced as int 
    std::cout<<&a_copy<<std::endl; 

    auto a_move = std::move(a);  // deduced as int 
    std::cout<<&a_move<<std::endl; 

}; 

出力:copy対int std :: move for ints

0x7fffffffe094 
0x7fffffffe098 
0x7fffffffe09c 
+10

'std :: move'は実際には何も移動しないことに注意してください。それはちょうどrvalue refへのキャストを実行するだけで、結果は有用にはrvalueですが、単純に 'a'という名前はありません。これらの2つの事実は、そこから移動するオブジェクトを提供することの一部ですが、実際に移動するオブジェクトではありません。だから、「動く」の後に尋ねることは赤いニシンです。 –

答えて

17

このの例では、違いはありません。私たちは3 intの値100で終わるでしょう。確かに異なるタイプとの違いかもしれません。たとえば、のは、vector<int>のようなものを考えてみましょう:

std::vector<int> a = {1, 2, 3, 4, 5}; // a has size 5 
auto a_copy = a;      // copy a. now we have two vectors of size 5 
auto a_move = std::move(a);   // *move* a into a_move 

最後の変数、a_moveは、aの内部ポインタの所有権を取得します。だから私たちは結局a_moveがサイズ5のベクトルですが、aは空になりました。 はcopyよりはるかに効率的です(1000文字列のベクトルであれば、a_copyは1000文字列のバッファを割り当て、1000文字列をコピーすることになりますが、a_moveは2つのポインタを割り当てます)。

他のいくつかのタイプでは、1が無効である可能性があります:多くの種類のために

std::unique_ptr<int> a{new int 42}; 
auto a_copy = a;   // error 
auto a_move = std::move(a); // OK, now a_move owns 42, but a points to nothing 

、何の違いは、しかしありません:

std::array<int, 100> a; 
auto a_copy = a;   // copy 100 ints 
auto a_move = std::move(a); // also copy 100 ints, no special move ctor 

より一般的には:

T a; 
auto a_copy = a;   // calls T(const T&), the copy constructor 
auto a_move = std::move(a); // calls T(T&&), the move constructor 
+0

ありがとうございます、あなたの答えは本当に役に立ちます。 'static_cast &&>'をstd :: moveとまったく同じものを使用しています(最初の例では)? –

+1

@ Person.Junkieはい、 'std :: move'はrvalue refへの静的キャストを実行しますが、キャストを書くよりも' std :: move() 'を優先します。これは(a)入力が少なくて(b)コード行の意図がはるかに明確になります。 – Barry

+2

@バリー:私は同意しない - それははるかに短いですが、_lie_です。 –

4

この例ではデフォルトのコピーとstd ::動きの違いは何ですか?

違いはありません。コピーするものは移動の要件を満たし、組み込み型の場合は移動をコピーとして実装します。

オブジェクトは新しいものと古い

間のいずれかの依存関係がありませんあり、移動した後、依存関係はありません。両方の変数は独立しています。

+0

... std :: moveの利点は何ですか?なぜですか? –

+2

@ Person.Junkieここですか?利点はありません。コードが混乱するという欠点があります。 – juanchopanza

+0

一般的には?なぜstd :: moveが存在するのでしょうか? 私は、std :: moveは、static_castを使用して、lvalue/rvalueをrvalueに変換することを知っています。 –

8

だけstd::moveを使用して左辺値をxvalueに変更するので、移動コンストラクタでの使用に適しています。 ssignment演算子。これらは組み込み型では存在しないため、この例ではmoveを使用しても違いはありません。

3

move-is-a-copyパラダイムは、この例のように、PODタイプ(またはPODタイプで構成された他のタイプで構成される)のすべてのデータ構造に適用されます。

FooBar両方の場合
struct Foo 
{ 
    int values[100]; 
    bool flagA; 
    bool flagB; 
}; 

struct Bar 
{ 
    Foo foo1; 
    Foo foo2; 
}; 

int main() 
{ 
    Foo f; 
    Foo fCopy = std::move(f); 
    Bar b; 
    Bar bCopy = std::move(b); 
    return 0; 
} 

両方が最終的にPODタイプの凝集体であるため、別のデータを移動するための意味のある方法は存在しない - それらのデータのいずれも間接的(点または参照他のメモリを所有していません)。したがって、このような場合、移動はコピーとして実装され、std::move()行の割り当て後にオリジナル(fb)は変更されません。

移動セマンティクスは、動的に割り当てられたメモリまたは固有のリソースでのみ意味のある形で実装できます。

+1

* "値の型で構成されているため、データを移動する意味がありません" * - ここでは値の型が正しいとは思わない。すべての標準ライブラリコンテナは値型であり、確かにデータを移動する意味のある方法があります。 –

+1

@BenjaminLindleyしかし、それらは値型の*構成*ではありません - 動的に割り当てられたメモリ(ポインタ型)を含んでいます。 – mbgda

+0

さて、structの中に 'std :: vector'を置くと、次のようになります:' struct Foo {std :: vector v; }; 'の場合、その構造体は値型で構成され、そのデータを移動するには意味のある方法があります。 –

関連する問題