合計 5 つの操作が必要です: 従来の "ビッグ 3" (コピー コンストラクター、コピー代入演算子、デストラクタ) と 2 つの新しい移動操作 (移動コンストラクター、移動代入演算子):
// destructor
~Map();
// copy constructor
Map(const Map& that);
// move constructor
Map(Map&& that)
{
impl_ = that.impl_;
that.impl_ = 0;
}
// copy assignment operator
Map& operator=(const Map& that);
// move assignment operator
Map& operator=(Map&& that)
{
using std::swap;
swap(impl_, that.impl_);
return *this;
}
移動割り当て演算子の背後にある基本的な考え方は、スワップを実行した後に再度検査しない場合swap(map1, map2)
と同じ観察可能な副作用があるということです。右辺値は prvalue または xvalue のいずれかであることを思い出してください。定義上、 prvalue を評価すると常に新しいオブジェクトが作成されるため、クライアントはprvalue で指定されたオブジェクトを 2 回検査することはできません。このトリックを確認する唯一の方法は、 などの xvalue から移動することですが、変更される可能性があることは明らかです。map1 = map2
map2
std::move(map_variable)
map_variable
コピー時にも例外セーフな代入が必要な場合は、コピー代入演算子 ( を取る) と移動代入演算子 ( を取る)の両方を一般化された代入演算子 ( を取る ) に組み合わせることができます。次に、必要な操作は合計 4 つだけです。const Map&
Map&&
Map
// exception safe copy/move assignment operator
Map& operator=(Map that)
{
using std::swap;
swap(impl_, that.impl_);
return *this;
}
代入演算子のこのバリアントは、引数を値で受け取ることに注意してください。引数が左辺値の場合、コピー コンストラクターが初期化that
し、引数が右辺値の場合、移動コンストラクターがジョブを実行します。std::swap
(また、すでに移動操作を提供している場合、特殊化によってさらに大幅なパフォーマンスが向上する可能性は低いことに注意してください。)