std::moveとstd::forward
std::moveで左辺値を右辺値にキャストし、std::forwardで値カテゴリーを保ちます。
「std::moveとstd::forward」はCoddyKit上の無料C++ Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC++ Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C++ Academyコースには全4レッスンが含まれています。
似ている2つの機能、それぞれ異なる役割
std::moveと std::forwardはいずれもコンパイル時のキャストです。見た目は似ていますが、異なる問題を解決します。
std::move:常に右辺値へキャスト
std::move(x)は、無条件に xを右辺値参照へキャストします。これにより、受け取る関数はそのリソースを奪えるようになります。
std::string s = "Hello";
std::string t = std::move(s); // move-constructs t from s
// s is now in a valid-but-unspecified statemoveを使う場合
std::moveは次の場面で使用します:
- ムーブコンストラクターとムーブ代入演算子
- ムーブを強制したい場合のローカル変数の返却(通常は不要です。多くの場合RVOが適用されます)
- 不要になったローカル変数をシンク関数に渡す場合
std::moveの実装
実際には、次の static_castを隠したものにすぎません:
template <typename T>
typename std::remove_reference<T>::type&& move(T&& t) noexcept {
return static_cast<typename std::remove_reference<T>::type&&>(t);
}std::forward:カテゴリを維持
転送参照(T&&)を使用するテンプレートでは、std::forward<T>(x)によって xを元のカテゴリ(左辺値または右辺値)に戻すようにキャストします。完全転送に使用します。
template <typename T>
void wrapper(T&& arg) {
target(std::forward<T>(arg)); // forwards as lvalue or rvalue depending on T
}転送が必要な理由
テンプレート内では、パラメーターに名前があるため、呼び出し側が右辺値を渡した場合でも左辺値になります。std::forwardによって元のカテゴリを取り戻せます。
std::forwardを使わない場合
forwardを使わなければ、すべての引数がラッパー内で左辺値として渡され、呼び出し側が意図したムーブセマンティクスが機能しなくなります。
template <typename T>
void wrapper(T&& arg) {
target(arg); // always lvalue — wrong
}forwardには必ずテンプレート引数を指定する
std::forward<T>には明示的なテンプレート引数が必要です。指定しないと、動作が正しくなりません。
完全転送の例
コンストラクター引数を転送するファクトリ関数は、効率性のために右辺値と左辺値の区別を維持します。
template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}ムーブは1回だけ
各オブジェクトからムーブするのは最大1回にしてください。ムーブ後は有効ですが状態は未規定です。通常は再代入するか、破棄します。再代入せずにムーブ元のオブジェクトを使用すると、気付きにくいバグにつながるおそれがあります。
経験則
簡単な考え方:
- 具体的な型があり、それをムーブしたい →
std::move - テンプレートパラメーターがあり、カテゴリを維持したい →
std::forward<T>
確認問題
パラメーターが T&& argであるテンプレート関数内で、argの左辺値・右辺値カテゴリを維持して転送するにはどうしますか?
まとめ
std::moveは無条件に右辺値へキャストします。リソースを奪いたい具体的なオブジェクトに使用してください。std::forward<T>はジェネリックテンプレート内で値カテゴリを維持します。完全転送に使用してください。
よくある質問
「std::moveとstd::forward」レッスンは無料ですか?
はい。「std::moveとstd::forward」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C++ Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C++ Academyコースには全4レッスンが含まれています。
「std::moveとstd::forward」で何を学びますか?
std::moveで左辺値を右辺値にキャストし、std::forwardで値カテゴリーを保ちます。 ブラウザで直接実行するハンズオンコードでC++ Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
C++ Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのC++ Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「std::moveとstd::forward」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このC++ Academyレッスンでコードを書いて実行できますか?
はい。すべてのC++ Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 左辺値と右辺値の違い
- 右辺値参照と&&構文
- std::moveとstd::forward
- ムーブコンストラクターとムーブ代入