サーチ…


値カテゴリの意味

C ++の式には、その式の結果に基づいて特定の値カテゴリが割り当てられます。式の値カテゴリは、C ++関数のオーバーロード解決に影響します。

値のカテゴリは、式に関する2つの重要な、別々のプロパティを決定します。 1つの特性は、その表現が同一性を有するかどうかである。変数名を持つオブジェクトを参照する場合、式は同一性を持ちます。変数名は式に関係しないかもしれませんが、オブジェクトにはまだ変数名が含まれています。

もう1つのプロパティは、式の値から暗黙的に移動することが合法かどうかです。より具体的には、式を関数パラメータとして使用する場合、r値のパラメータ型にバインドするかどうかを指定します。

C ++は、lvalue(識別可能ではあるが移動可能ではない式)、xvalue(識別可能な式は移動可能)、およびprvalue(識別可能な式がない式)の3つの値のカテゴリを定義しています。 C ++にはIDがなく、移動できない式はありません。

C ++では、glvalue(ID付きの式)とrvalue(移動可能な式)の2つの値カテゴリが定義されています。これらは、先のカテゴリの有用なグループ分けとして機能する。

このグラフはイラストとして役立ちます:

C ++言語の値カテゴリのグラフ

値段付け

prvalue(純粋な値)式は、同一性がない式で、その評価は通常オブジェクトの初期化に使用され、暗黙的に移動できます。これには以下のものが含まれますが、これらに限定されません。

  • 一時オブジェクトを表す式std::string("123")
  • 参照を返さない関数呼び出し式
  • リテラル(文字列リテラルを除く - これは左辺値です)、 1true0.5f 、または'a'
  • ラムダ式

組み込みアドレスの演算子( & )は、これらの式には適用できません。

xvalue

xvalue(eXpiring値)式は、IDを持ち、暗黙的に移動できるオブジェクトを表す式です。 xvalue式の一般的な考え方は、それらが表現するオブジェクトがすぐに破棄されることになり(したがって、「エキサイティング」な部分)、暗黙のうちにそこから移動することは問題ないということです。

与えられた:

struct X { int n; };
extern X x;

4;                   // prvalue: does not have an identity
x;                   // lvalue
x.n;                 // lvalue
std::move(x);        // xvalue
std::forward<X&>(x); // lvalue
X{4};                // prvalue: does not have an identity
X{4}.n;              // xvalue: does have an identity and denotes resources
                     // that can be reused

左辺値

左辺式は、同一性を持つ式ですが、暗黙的に移動することはできません。これらの中には、変数名、関数名、組み込み逆参照演算子である式、左辺値参照を参照する式からなる式があります。

典型的な左辺値は単なる名前ですが、左辺値は他の味でも来ることができます:

struct X { ... };

X x;         // x is an lvalue
X* px = &x;  // px is an lvalue
*px = X{};   // *px is also an lvalue, X{} is a prvalue

X* foo_ptr();  // foo_ptr() is a prvalue
X& foo_ref();  // foo_ref() is an lvalue

さらに、ほとんどのリテラル(たとえば4'x'など)はprvalueですが、文字列リテラルは左辺値です。

glvalue

glvalue(「一般化された左辺値」)式は、移動可能かどうかにかかわらず、同一性を持つ式です。このカテゴリには、lvalues(同一性はあるが移動できない式)とxvalues(同一性を持ち、移動可能な式)が含まれますが、prvalues(同一性のない式)は除きます。

式に名前がある場合、それはglvalueです。

struct X { int n; };
X foo();

X x;
x; // has a name, so it's a glvalue
std::move(x); // has a name (we're moving from "x"), so it's a glvalue
              // can be moved from, so it's an xvalue not an lvalue

foo(); // has no name, so is a prvalue, not a glvalue
X{};   // temporary has no name, so is a prvalue, not a glvalue
X{}.n; // HAS a name, so is a glvalue. can be moved from, so it's an xvalue

右値

rvalue式は、同一性を持っているかどうかにかかわらず、暗黙的に移動できる任意の式です。

より正確には、rvalue式は、 T && (ここでTexprの型です)型のパラメータをとる関数の引数として使用できます。このような関数の引数には、rvalue式のみを引数として与えることができます。非右辺の式が使用されている場合、過負荷解決はrvalue参照パラメータを使用しない関数を選択します。そして、存在しなければ、あなたはエラーを受け取ります。

rvalue式のカテゴリには、すべてのxvalue式とprvalue式、およびそれらの式のみが含まれます。

標準ライブラリ関数std::moveは、非右辺の式を右辺に明示的に変換するために存在します。より具体的には、式をxvalueに変えます。これは、前回のIDなしのprvalue式であっても、 std::moveパラメータとして渡すことで、ID(関数のパラメータ名)を取得してxvalueになるからです。

次の点を考慮してください。

std::string str("init");                       //1
std::string test1(str);                        //2
std::string test2(std::move(str));             //3

str = std::string("new value");                //4 
std::string &&str_ref = std::move(str);        //5
std::string test3(str_ref);                    //6

std::stringは、 std::string&&タイプの単一のパラメータを取るコンストラクタがあります。これは一般に「ムーブコンストラクタ」と呼ばれます。ただし、式str値カテゴリはrvalue(特に左辺値)ではないため、そのコンストラクタをオーバーロードと呼び出すことはできません。代わりに、 const std::string& overload(コピーコンストラクタ)を呼び出します。

3行目は物事を変えます。 std::moveの戻り値はT&&で、 Tは渡されたパラメータの基本型です。したがって、 std::move(str)std::string&&返します。戻り値がrvalue参照である関数呼び出しはrvalue式(特にxvalue)であるため、 std::string移動コンストラクタを呼び出すことができstd::string 。 3行目の後、 strが移動しました(現在の内容は未定義です)。

4行目は一時的にstd::string代入演算子に渡しstd::string 。これにはstd::string&&をとるオーバーロードがあります。式std::string("new value")はrvalue式(特にprvalue)であるため、そのオーバーロードを呼び出すことがあります。したがって、一時的なstrに移動され、未定義の内容は特定の内容に置き換えられstr

5行目は、 strを参照するstr_refという名前のstr_ref参照を作成しstr 。これは、値のカテゴリが混乱するところです。

str_refstd::string右辺値参照ですが、式str_ref値カテゴリは右辺値ではありません 。それは左辺値式です。はい、そうです。このため、 std::string移動コンストラクタを式str_refで呼び出すことはできません。したがって、行6はstrの値をstrコピーtest3

それを移動するには、 std::move再度使用する必要があります。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow