std::move
| ヘッダ <utility>
|
||
template< class T >
typename std::remove_reference<T>::type&& move( T&& t ) noexcept;
|
(C++11以上) (C++14未満) |
|
template< class T >
constexpr std::remove_reference_t<T>&& move( T&& t ) noexcept;
|
(C++14以上) | |
std::move で定義されている。これは、オブジェクトが「ムーブ元」になる可能性があること、すなわちから別のオブジェクトへのリソースの効率的な転送を許すことをt示すtために使用される。
特に、std::moveは、その引数を識別するxvalue式tを生成する。これは、static_castへの右辺値参照型へのキャストと正確に等価である。
パラメータ
| t | - | 移動対象のオブジェクト |
戻り値
static_cast < typename std:: remove_reference < T > :: type && > ( t )
注記
右辺値参照パラメータを受け入れる関数(
ムーブコンストラクタ
、
ムーブ代入演算子
、および
std::vector::push_back
のような通常のメンバ関数を含む)は、
オーバーロード解決
によって、
右辺値
引数(一時オブジェクトのような
prvalue
や、
std::move
によって生成される
xvalue
など)で呼び出されたときに選択されます。引数がリソースを所有するオブジェクトを識別する場合、これらのオーバーロードは、引数によって保持されているリソースを
ムーブ
するオプションを持ちますが、必須ではありません。例えば、リンクリストのムーブコンストラクタは、リストの先頭へのポインタをコピーし、個々のノードを割り当ててコピーする代わりに、引数に
nullptr
を格納するかもしれません。
rvalue reference
の変数名は
lvalues
であり、
xvalues
に変換する必要があるため、rvalue referenceパラメータを受け入れる関数オーバーロードにバインドされます。これが、
move constructors
と
move assignment operators
が通常
std::move
を使用する理由です:
// シンプルなムーブコンストラクタ A(A&& arg) : member(std::move(arg.member)) // 式 "arg.member" は左辺値 {} // シンプルなムーブ代入演算子 A& operator=(A&& other) { member = std::move(other.member); return *this; }
唯一の例外は、関数パラメータの型が 転送参照 (型テンプレートパラメータへの右辺値参照のように見える)である場合で、この場合 std::forward が代わりに使用されます。
明示的に指定されていない限り、移動されたすべての標準ライブラリオブジェクトは「有効だが未規定の状態」に置かれます。これは、オブジェクトのクラス不変条件が保持されることを意味します(そのため、事前条件のない関数、例えば代入演算子などは、オブジェクトが移動された後でも安全に使用できます):
std::vector<std::string> v; std::string str = "example"; v.push_back(std::move(str)); // strは有効だが未指定の状態になる str.back(); // size() == 0の場合未定義動作: back()には事前条件 !empty()がある if (!str.empty()) str.back(); // OK, empty()には事前条件がなく、back()の事前条件が満たされている str.clear(); // OK, clear()には事前条件がない
また、xvalue引数で呼び出された標準ライブラリ関数は、その引数がオブジェクトへの唯一の参照であると仮定する場合があります。もしその引数がlvalueから
std::move
で構築された場合、エイリアシングチェックは行われません。しかし、標準ライブラリ型の自己ムーブ代入は、オブジェクトを有効な(ただし通常は未指定の)状態にすることが保証されています:
std::vector<int> v = {2, 3, 3}; v = std::move(v); // vの値は不定
例
#include <iomanip> #include <iostream> #include <string> #include <utility> #include <vector> int main() { std::string str = "Salut"; std::vector<std::string> v; // push_back(const T&) オーバーロードを使用 // 文字列のコピーコストが発生する v.push_back(str); std::cout << "After copy, str is " << std::quoted(str) << '\n'; // 右辺値参照 push_back(T&&) オーバーロードを使用 // 文字列のコピーは発生せず、代わりにstrの内容が // ベクターに移動される。コストは低いが、 // strが空になる可能性がある v.push_back(std::move(str)); std::cout << "After move, str is " << std::quoted(str) << '\n'; std::cout << "The contents of the vector are {" << std::quoted(v[0]) << ", " << std::quoted(v[1]) << "}\n"; }
出力例:
After copy, str is "Salut"
After move, str is ""
The contents of the vector are {"Salut", "Salut"}
関連項目
(C++11) |
関数の引数を転送し、その値カテゴリを保持するために型テンプレート引数を使用する (関数テンプレート) |
(C++11) |
ムーブコンストラクタが例外を投げない場合、引数をxvalueに変換する (関数テンプレート) |
(C++11) |
要素の範囲を新しい位置に移動する (関数テンプレート &アルゴリズム関数オブジェクト) |
(C++20) |