45

私はunique_ptrと右辺値移動の哲学と混同しています。

2つのコレクションがあるとしましょう。

std::vector<std::auto_ptr<int>> autoCollection;
std::vector<std::unique_ptr<int>> uniqueCollection;

アルゴリズムが内部で何をしているのか、おそらく内部ピボットコピーなどを作成しているのかわからないため、auto_ptrから所有権を奪うため、次のことが失敗すると予想されます。

std::sort(autoCollection.begin(), autoCollection.end());

私はこれを取得します。そして、コンパイラはこれを正しく禁止します。

しかし、私はこれを行います:

std::sort(uniqueCollection.begin(), uniqueCollection.end());

そして、これはコンパイルされます。そして、その理由がわかりません。unique_ptrsをコピーできるとは思いませんでした。これは、ピボット値を取得できないため、並べ替えの効率が低下することを意味しますか?それとも、このピボットは実際には動きであり、実際にはauto_ptrsのコレクションと同じくらい危険であり、コンパイラーによって許可されるべきではありませんか?

重要な情報が不足していると思うので、誰かが私にああを提供してくれるのを心待ちにしています!一瞬。

4

3 に答える 3

55

技術よりも哲学の問題だと思います:)

根本的な問題は、移動とコピーの違いは何ですか。私は技術的/標準主義的な言語に飛び込むことはしません、それを簡単にやってみましょう:

  • コピー:別の同一のオブジェクトを作成します(または、少なくとも、同等に比較する必要があるオブジェクト)
  • 移動:オブジェクトを取得して別の場所に配置します

あなたが言ったように、コピーの観点から移動を実装することは可能です:新しい場所にコピーを作成し、元の場所を破棄します。ただし、そこには2つの問題があります。1つはパフォーマンスに関するもので、もう1つはRAIIに使用されるオブジェクトに関するものです。2つのうちどちらが所有権を持つ必要がありますか?

適切なMoveコンストラクターは、次の2つの問題を解決します。

  • 元のオブジェクトは破棄されるため、どのオブジェクトが所有権を持っているかは明らかです。新しいオブジェクト
  • したがって、ポイントされたリソースをコピーする必要がないため、効率が向上します。

auto_ptrとはこれunique_ptrを非常によく表しています。

auto_ptrあなたはねじれたコピーセマンティクスを持っています:オリジナルとコピーは等しく比較されません。移動セマンティクスに使用できますが、どこかでポイントされたオブジェクトを失うリスクがあります。

一方、それunique_ptrはまさにそれです。リソースの一意の所有者を保証するため、コピーとそれに続く不可避の削除の問題を回避できます。また、コンパイル時もコピーなしが保証されます。したがって、コピーの初期化を試みない限り、コンテナに適しています。

typedef std::unique_ptr<int> unique_t;
typedef std::vector< unique_t > vector_t;

vector_t vec1;                           // fine
vector_t vec2(5, unique_t(new Foo));     // Error (Copy)
vector_t vec3(vec1.begin(), vec1.end()); // Error (Copy)
vector_t vec3(make_move_iterator(vec1.begin()), make_move_iterator(vec1.end()));
    // Courtesy of sehe

std::sort(vec1.begin(), vec1.end()); // fine, because using Move Assignment Operator

std::copy(vec1.begin(), vec1.end(), std::back_inserter(vec2)); // Error (copy)

したがって、(とは異なり)コンテナで使用できますが、タイプがサポートしていないコピーを伴うため、多くの操作は不可能になります。unique_ptrauto_ptr

残念ながら、Visual Studioは標準の施行にかなり緩慢である可能性があり、コードの移植性を確保するために無効にする必要がある拡張機能もいくつかあります...標準をチェックするために使用しないでください:)

于 2010-05-21T06:44:08.430 に答える
14

unique_ptr、moveコンストラクターを使用して移動されています。unique_ptr移動可能ですが、CopyConstructableではありません。

ここに右辺値の参照に関するすばらしい記事があります。それらについてまだ読んでいない場合、または混乱している場合は、見てください!

于 2010-05-20T18:29:56.977 に答える
7

std::sort常に各オブジェクトのライブコピーが1つしかない限り、移動操作でのみ機能し、コピーは機能しません。これは、インプレースで作業するよりも弱い要件です。原則として、別の配列を一時的に割り当て、すべてのオブジェクトを並べ替えるときに移動できるためです。

たとえばstd::vector<std::unique_ptr<T>>、容量を超えると、より大きなベクトルにストレージを割り当ててから、すべてのオブジェクトを古いストレージから新しいストレージに移動します。これはインプレース操作ではありませんが、完全に有効です。

結局のところ、クイックソートやヒープソートなどのソートアルゴリズムは、実際には問題なくインプレースで機能します。クイックソートのパーティションルーチンは、内部でstd :: swapを使用します。これは、関連する両方のオブジェクトの移動操作としてカウントされます。ピボットを選択するときの1つのトリックは、範囲内の最初の要素とそれを交換することです。これにより、パーティショニングが完了するまでピボットが移動することはありません。

于 2013-02-20T09:52:46.647 に答える