0Pricing
C++ Academy · レッスン

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 state

moveを使う場合

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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 左辺値と右辺値の違い
  2. 右辺値参照と&&構文
  3. std::moveとstd::forward
  4. ムーブコンストラクターとムーブ代入
← C++ Academyに戻る