2

私は以下の投稿を読みました。これは、移動のセマンティクスに関する非常に優れた洞察を提供します。

誰かが私に移動セマンティクスを説明できますか?

しかし、私はまだ移動セマンティクスに関する次のことを理解できていません-

  1. コピーの省略とRVOは、移動コンストラクターがなくてもクラスで機能しますか?

  2. クラスにmoveコンストラクターがない場合でも、STLコンテナーにはmoveコンストラクターがあります。のような操作のために

std::vector<MyClass> vt = CreateMyClassVector();

ソートなどの操作を実行するために。STLが内部で移動セマンティクスを活用して、移動コンストラクターを必要としないコピーの省略やRVOなどの操作を使用して内部でそのような操作を改善できないのはなぜですか。

3.以下の場合、移動セマンティクスの恩恵を受けますか?

std::vector< int > vt1(1000000, 5); // Create and initialize 1 million entries with value 5

std::vector< int > vt2(std::move(vt1)); // move vt1 to vt2

整数はプリミティブ型であるため、整数要素を移動しても利点はありません。または、ここで移動操作の後、vt2は単にヒープ内のvt1メモリを指し、vt1はnullに設定されます。実際に何が起こっているのですか?後者の場合、ポイント2でさえ、クラスのmoveコンストラクターは必要ない可能性があります。

4. std :: move on lvalueを使用してpush_back()が呼び出された場合。

    std::vector<MyClass> vt;

    for(int i=0; i<10; ++i)
    {
        vt.push_back(MyClass());
    }

    MyClass obj;

    vt.push_back(std::move(obj));

ベクトルには連続したメモリ割り当てがあり、objはメモリ内の別の場所で定義されているため、セマンティクスを移動してobjメモリをベクトルvtの連続したメモリ領域に移動します。この場合、メモリを移動するのはメモリをコピーするのと同じくらい優れていません。ヒープの異なる領域にあるメモリを指すポインタを移動するだけで、連続するメモリ要件をベクトル化します。

よろしくお願いします!

[元々は移動セマンティクスの説明として投稿されましたが、コンテキストが変更されたため、新しい質問として古い質問をできるだけ早く削除するため、少し投稿します。]

4

2 に答える 2

2

コピーの省略とRVOは、移動コンストラクターがなくてもクラスで機能しますか?

はい、RVOはまだ機能します。実際、コンパイラは以下を選択することが期待されています。

  • RVO(可能な場合)
  • 建設を移動する(可能な場合)
  • コピー構築(最後の手段)

STLが内部的に移動セマンティクスを活用して、移動コンストラクターを必要としないコピーの省略やRVOなどの操作を使用して、このような操作を内部的に改善できないのはなぜですか?

STLコンテナ、格納されているタイプに関係なく移動可能です。ただし、コンテナ内のオブジェクトに対する操作にはオブジェクトの連携が必要であるため、(たとえば)ソートでは、オブジェクトが移動可能な場合にのみオブジェクトを移動できます。

整数はプリミティブ型であるため、以下の場合[...]の移動セマンティクスの恩恵を受けますか?

はい、そうです。コンテナ内容に関係なく移動できるからです。あなたが推測したように、st2からメモリを盗みますst1。ただし、移動後の状態st1は特定されていないため、ストレージが無効になることは保証できません。

左辺値を使用してapush_back()が呼び出された場合std::move[何が起こるか]?

左辺値のタイプの移動コンストラクターが呼び出されます。通常、これには、元のファイルの宛先へのビット単位のコピーと、元の値の無効化が含まれます。

一般に、移動コンストラクターのコストはsizeof(object);に比例します。たとえば、sizeof(std::string)文字数に関係なく安定しstd::stringています。これは、実際には、これらの文字がヒープに格納されているため(少なくとも十分な数の文字がある場合)、ヒープストレージへのポインタのみが移動されるためです(さらに一部の文字もメタデータ)。

于 2013-01-31T10:24:13.227 に答える
1
  1. はい。
  2. 彼らは可能な限りそうします。
  3. はい。std::vectorすべての要素のコピーを回避する移動コンストラクターがあります。
  4. それはまだ隣接しています。

例えば

struct MyClass
{         
     MyClass(MyClass&& other) 
         : xs(other.xs), size(other.size)
     {
          other.xs = nullptr;
     }

     MyClass(const MyClass& other) 
       : xs(new int[other.size]), size(other.size)
     { 
         memcpy(xs, other.xs, size);
     }

     ~MyClass() 
     {               
         delete[] xs;
     }

     int* xs;
     int size;
}

移動コンストラクターのみxssize使用し、ベクターにコピーする必要があります(連続メモリの場合)。ただしmemcpy、コピーコンストラクターの場合のようにメモリ割り当てを実行する必要はありません。

于 2013-01-31T06:33:50.040 に答える