17

2011 年以降、コピーとムーブの両方の割り当てがあります。ただし、この回答は、リソース管理クラスの場合、代入演算子は1つしか必要ないことを非常に説得力を持って主張しています。たとえばstd::vector、これは次のようになります

vector& vector::operator=(vector other)
{
  swap(other);
  return*this;
}

ここで重要な点は、引数が値によって取得されることです。otherこれは、適切な関数本体が入力された時点で、 (可能であればムーブ コンストラクターによって、そうでない場合はコピー コンストラクターによって)の構築によって多くの作業が既に行われていることを意味します。したがって、これにより、コピーと移動の両方の割り当てが自動的に正しく実装されます。

これが正しければ、なぜ (少なくともこのドキュメントによると)このように実装されてstd::vector いないのでしょうか?


これがどのように機能するかを説明するために編集します。other次の例で、上記のコードで何が起こるかを考えてみましょう

void foo(std::vector<bar> &&x)
{
  auto y=x;             // other is copy constructed
  auto z=std::move(x);  // other is move constructed, no copy is ever made.
  // ...
}
4

2 に答える 2

7

要素型がコピー可能でない場合、またはコンテナが強力な例外保証を尊重しない場合、宛先オブジェクトに十分な容量がある場合、コピー代入演算子は割り当てを回避できます。

vector& operator=(vector const& src)
{
    clear();
    reserve(src.size());  // no allocation if capacity() >= src.size()
    uninitialized_copy_n(src.data(), src.size(), dst.data());
    m_size = src.size();
}
于 2015-11-20T23:39:41.070 に答える
-2

実際には、3 つの代入演算子が定義されています。

vector& operator=( const vector& other );
vector& operator=( vector&& other );
vector& operator=( std::initializer_list<T> ilist );

あなたの提案vector& vector::operator=(vector other)は、コピーとスワップのイディオムを使用しています。つまり、オペレーターが呼び出されると、元のベクターがパラメーターにコピーされ、ベクター内のすべての項目がコピーされます。次に、このコピーは と交換されthisます。コンパイラはそのコピーを省略できるかもしれませんが、そのコピー省略はオプションであり、移動セマンティクスは標準です。

そのイディオムを使用して、コピー代入演算子を置き換えることができます。

vector& operator=( const vector& other ) {
    swap(vector{other}); // create temporary copy and swap
    return *this;
}

いずれかの要素をコピーすると、この関数もスローされます。

移動代入演算子を実装するには、コピーを省略します。

vector& operator=( vector&& other ) {
    swap(other);
    return *this;
}

スローしないためswap()、ムーブ代入演算子もスローしません。

initializer_list-assignment は、move 代入演算子と匿名の一時変数を使用して簡単に実装することもできます。

vector& operator=( std::initializer_list<T> ilist ) {
    return *this = vector{ilist};
}

移動代入演算子を使用しました。initializer_list結果として、要素のインスタンス化の 1 つがスローされたときにのみ、割り当て operatortpr がスローされます。

私が言ったように、コンパイラはコピー代入のコピーを省略できるかもしれません。ただし、コンパイラはその最適化を実装する義務はありません。移動セマンティクスを実装する必要があります。

于 2015-11-20T23:28:57.990 に答える