C++標準ライブラリ提供クラスのムーブ代入演算子による自己代入操作について。
2019-09-02追記:C++17現在はLWG 2468によって、自己ムーブ代入操作による未定義動作(undefined behavior)は回避される。ただし別途規定のない場合、自己ムーブ代入後は “有効だが未規定な状態(valid but unspecified state)” となることに注意(→id:yohhoy:20120616)。
2021-09-11追記:C++標準ライブラリ全域にわたる自己ムーブ代入への対処の明確化のため、LWG 2839が採択されC++2b(C++23) WD仕様に適用されている。ユーザからみた振る舞いはC++17時点と同じ。またClang 3.6*1から自明な自己ムーブ代入を検知する-Wself-move警告オプションが追加された。
2022-09-29追記:GCC 13から-Wself-move警告オプションが追加される。
要約:
- C++標準ライブラリ提供のクラス(クラステンプレート)では、自己ムーブ代入操作は
未定義動作(undefined behavior)を引き起こす。 - 例外的に、文字列クラステンプレート
std::basic_string
は自己ムーブ代入操作がwell-definedとなっている(何もしない)。 - おまけ:ユーザ定義型における自己ムーブ代入操作は無関係。単にユーザ定義型でのムーブ代入演算子実装に依存する。
std::vector<int> v = { /*...*/ }; std::string s = /*...*/; v = std::move(v); // NG: 未定義動作 s = std::move(s); // OK: 何もしない
関数(含むメンバ関数)の引数にrvalue参照型(T&&
)を取る場合、個別の要件が無いかぎりは、同引数がユニークなオブジェクトを指す、つまりメンバ関数であれば引数が*this
を指すことが無いと仮定した標準ライブラリ実装が許される。C++11(N3337) 17.6.4.9/p1, 21.4.2/p23*2より一部引用(下線部は強調)。
1 Each of the following applies to all arguments to functions defined in the C++ standard library, unless explicitly stated otherwise.
- (snip)
- If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument. [Note: If the parameter is a generic parameter of the form
T&&
and an lvalue of typeA
is bound, the argument binds to an lvalue reference (14.8.2.1) and thus is not covered by the previous sentence. -- end note] [Note: If a program casts an lvalue to an xvalue while passing that lvalue to a library function (e.g. by calling the function with the argumentmove(x)
), the program is effectively asking that function to treat that lvalue as a temporary. The implementation is free to optimize away aliasing checks which might be needed if the argument was an lvalue. -- end note]
basic_string<E,T,A>& operator=(basic_string<E,T,A>&& str) noexcept;
23 If*this
andstr
are the same object, the member has no effect.
関連URL
- c++ - What does the standard library guarantee about self move assignment? - Stack Overflow
- c++ - Behaviour of move-assignment to self - Stack Overflow
*1:http://blog.llvm.org/2015/02/llvm-36-release.html
*2:basic_string クラステンプレートのテンプレートパラメータ名は略記。