ProgrammingC++開発者

C++における'lvalue'と'rvalue'とは何ですか?それらの違い、関数への渡し方、そしてrvalue参照(rvalue references)が登場した理由を説明してください。

Hintsage AIアシスタントで面接を突破

答え

C++においてlvalue(左辺値)は、メモリ内のオブジェクトを参照する式であり、名前があり参照できるもの(例えば変数)です。rvalue(右辺値)は、一時的な値であり名前を持たず、従来の意味でのオブジェクトではありません(例えば、a + bの結果や、リテラルの5など)。

lvalueはアドレスを取ることができますが、rvalueは取ることができません(rvalue参照が登場する前は)。関数に渡す方法には次のものがあります:

  • 通常の参照:void foo(const std::string& s); — lvalueとrvalueを受け取ります。
  • Lvalue参照:void bar(std::string& s); — lvalueのみを受け取ります。
  • Rvalue参照(C++11以降):void baz(std::string&& s); — rvalueのみを受け取ります。

例:

void takeValue(std::string& s) { } // lvalue void takeRValue(std::string&& s) { } // rvalue std::string s = "hello"; takeValue(s); // OK, lvalue takeRValue(std::string("hi")); // OK, rvalue

rvalue参照は、一時オブジェクトの効率的な受け渡しのために必要で、主にリソースを移動させるためのムーブセマンティクスに使用され、コピーするのではなくリソースを移動します。

トリッキーな質問

std::move(obj)の式はどのタイプの参照(lvalueまたはrvalue)を取得しますか?std::moveを適用した後、オブジェクトはどのカテゴリになりますか?

答え:

std::move(obj)は常にrvalue参照(T&&)を返しますが、オブジェクト自体はlvalueのままであり、単に明示的な変換が適用されるだけです。この後、オブジェクトには非常に注意して対処する必要があります(未定義ですが有効な状態にある可能性があります)。

例:

std::string s = "data"; std::string d = std::move(s); // dはsのデータを受け取りますが、sは空になります

このテーマに関する知識不足による実際のエラーの例。


事例

大規模なプロジェクトで、ある開発者が一時オブジェクトをlvalue参照T&で渡していました(T&&またはconst T&の代わりに)。これによりコンパイルエラーが発生し、最適でないコピーが行われました—ムーブセマンティクスが使用されず、パフォーマンスが40%低下しました。


事例

フロントエンドエンジンで、std::moveを変数に誤って適用し、その後再び使用されることがありました。その結果、変数は「破壊された」状態になり、クラッシュやレンダースレッドの異常終了が発生しました。


事例

シリアル化ライブラリで、std::vector<T>のコンテナを関数にlvalueとして渡しましたが、移動を期待していました。移動の代わりに、多くの要素を高価にコピーすることになり、大きな配列のシリアル化時間が急激に悪化しました。