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
はその引数 t
を表す xvalue 式を生成します。 これは右辺値参照型への static_cast と正確に同等です。
目次 |
[編集] 引数
t | - | ムーブされるオブジェクト |
[編集] 戻り値
static_cast<typename std::remove_reference<T>::type&&>(t)。
[編集] ノート
右辺値参照の引数を取る関数 (ムーブコンストラクタ、ムーブ代入演算子および std::vector::push_back のような普通のメンバ関数を含みます) は、右辺値引数 (prvalue (一時オブジェクトなど) または xvalue (std::move
によって生成されたものなど) のいずれか) を指定して呼んだときに、オーバーロード解決によって選択されます。 引数がリソースを所有するオブジェクトを表す場合、これらのオーバーロードは、引数が保持しているあらゆるリソースをムーブすることができます (そうしなければならないわけではありません)。 例えば、連結リストのムーブコンストラクタは、個々のノードを確保してコピーする代わりに、リストの先頭を指すポインタをコピーし、引数に nullptr を格納することができます。
右辺値参照の変数の名前は左辺値であり、右辺値参照の引数を取る関数オーバーロードに束縛されるためには xvalue に変換されなければなりません。 これはムーブコンストラクタやムーブ代入演算子がなぜ一般的に std::move を使用するのかの理由です。
// 単純なムーブコンストラクタ A(A&& arg) : member(std::move(arg.member)) // 式「arg.member」は lvalue です。 {} // 単純なムーブ代入演算子 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() があります。 str.clear(); // OK。 clear() は事前条件がありません。
また、 xvalue 引数を指定して呼ばれた標準ライブラリの関数は、引数がオブジェクトへの唯一の参照であると仮定することがあります。 もしそれが std::move
で左辺値から構築された場合、エイリアシングのチェックは行われません。 これは、標準ライブラリのムーブ代入演算子は自己代入チェックを行う必要がないことを意味します。
std::vector<int> v = {2, 3, 3}; v = std::move(v); // v の値は未規定です。
[編集] 例
#include <iostream> #include <utility> #include <vector> #include <string> int main() { std::string str = "Hello"; std::vector<std::string> v; // push_back の const T& オーバーロードを使用します。 // これは str をコピーするコストがかかることを意味します。 v.push_back(str); std::cout << "After copy, str is \"" << str << "\"\n"; // push_back の T&& (右辺値参照) オーバーロードを使用します。 // これは文字列をコピーせず、代わりに str の内容が vector 内に // ムーブされることを意味します。 // これは上の方法より安価ですが、 str が空になるかもしれません。 v.push_back(std::move(str)); std::cout << "After move, str is \"" << str << "\"\n"; std::cout << "The contents of the vector are \"" << v[0] << "\", \"" << v[1] << "\"\n"; }
出力例:
After copy, str is "Hello" After move, str is "" The contents of the vector are "Hello", "Hello"
[編集] 関連項目
(C++11) |
関数の引数を転送します (関数テンプレート) |
(C++11) |
ムーブコンストラクタが例外を投げない場合、右辺値参照を取得します (関数テンプレート) |
(C++11) |
指定範囲の要素を新しい位置にムーブします (関数テンプレート) |