前書き
ISOC ++ 11(正式にはISO / IEC 14882:2011)は、C ++プログラミング言語の標準の最新バージョンです。これには、いくつかの新機能と概念が含まれています。次に例を示します。
- 右辺値参照
- xvalue、glvalue、prvalue式の値のカテゴリ
- セマンティクスを移動
新しい式の値カテゴリの概念を理解したい場合は、右辺値と左辺値の参照があることに注意する必要があります。右辺値が非const右辺値参照に渡されることを知っている方が良いです。
int& r_i=7; // compile error
int&& rr_i=7; // OK
ワーキングドラフトN3337(公開されたISOC ++ 11標準に最も類似したドラフト)のLvaluesおよびrvaluesというタイトルのサブセクションを引用すると、値カテゴリの概念を直観的に理解できます。
3.10左辺値と右辺値[basic.lval]
1式は、図1の分類に従って分類されます。
- 左辺値(割り当て式の左側に左辺値が現れる可能性があるため、これまではいわゆる)は、関数またはオブジェクトを指定します。[例:Eがポインター型の式の場合、* Eは、Eが指すオブジェクトまたは関数を参照する左辺値式です。別の例として、戻り値の型が左辺値参照である関数を呼び出した結果は左辺値です。—例を終了]
- xvalue(「eXpiring」値)は、通常、その寿命の終わり近くにあるオブジェクトも指します(そのため、たとえば、リソースが移動される場合があります)。xvalueは、右辺値参照を含む特定の種類の式の結果です(8.3.2)。[例:戻り値の型が右辺値参照である関数を呼び出した結果はx値です。—例を終了]
- glvalue(「一般化された」lvalue)は、lvalueまたはxvalueです。
- 右辺値(割り当て値の右側に右辺値が現れる可能性があるため、歴史的に呼ばれる)は、x値、
一時オブジェクト(12.2)またはそのサブオブジェクト、あるいは
オブジェクトに関連付けられていない値です。
- prvalue(「純粋な」右辺値)は、x値ではない右辺値です。[例:戻り値の型が
参照ではない関数を呼び出した結果は、prvalueです。12、7.3e5、
true などのリテラルの値もprvalueです。—例を終了]
すべての式は、この分類法の基本的な分類の1つであるlvalue、xvalue、またはprvalueに属しています。式のこのプロパティは、その値カテゴリと呼ばれます。
しかし、このサブセクションが概念を明確に理解するのに十分であるかどうかはよくわかりません。「通常」は実際には一般的ではなく、「その寿命の終わり近く」は実際には具体的ではなく、「右辺値参照の関与」はあまり明確ではないためです。および「例:戻り値の型が右辺値参照である関数を呼び出した結果はx値です。」蛇が尻尾を噛んでいるように聞こえます。
主な値のカテゴリ
すべての式は、1つの主要な値カテゴリに属しています。これらの値カテゴリは、lvalue、xvalue、およびprvalueカテゴリです。
左辺値
式Eがlvalueカテゴリに属するのは、Eが、ALREADYがEの外部からアクセスできるようにするID(アドレス、名前、またはエイリアス)を持っているエンティティを参照する場合のみです。
#include <iostream>
int i=7;
const int& f(){
return i;
}
int main()
{
std::cout<<&"www"<<std::endl; // The expression "www" in this row is an lvalue expression, because string literals are arrays and every array has an address.
i; // The expression i in this row is an lvalue expression, because it refers to the same entity ...
i; // ... as the entity the expression i in this row refers to.
int* p_i=new int(7);
*p_i; // The expression *p_i in this row is an lvalue expression, because it refers to the same entity ...
*p_i; // ... as the entity the expression *p_i in this row refers to.
const int& r_I=7;
r_I; // The expression r_I in this row is an lvalue expression, because it refers to the same entity ...
r_I; // ... as the entity the expression r_I in this row refers to.
f(); // The expression f() in this row is an lvalue expression, because it refers to the same entity ...
i; // ... as the entity the expression f() in this row refers to.
return 0;
}
xvalues
式Eは、次の場合に限り、xvalueカテゴリに属します。
—暗黙的または明示的に、戻り値の型が返されるオブジェクトの型への右辺値参照である関数の呼び出しの結果、または
int&& f(){
return 3;
}
int main()
{
f(); // The expression f() belongs to the xvalue category, because f() return type is an rvalue reference to object type.
return 0;
}
—オブジェクト型への右辺値参照へのキャスト、または
int main()
{
static_cast<int&&>(7); // The expression static_cast<int&&>(7) belongs to the xvalue category, because it is a cast to an rvalue reference to object type.
std::move(7); // std::move(7) is equivalent to static_cast<int&&>(7).
return 0;
}
—オブジェクト式がxvalueである非参照型の非静的データメンバーを指定するクラスメンバーアクセス式、または
struct As
{
int i;
};
As&& f(){
return As();
}
int main()
{
f().i; // The expression f().i belongs to the xvalue category, because As::i is a non-static data member of non-reference type, and the subexpression f() belongs to the xvlaue category.
return 0;
}
—最初のオペランドがxvalueで、2番目のオペランドがデータメンバーへのポインターであるメンバーへのポインター式。
上記のルールの効果は、オブジェクトへの名前付き右辺値参照は左辺値として扱われ、オブジェクトへの名前なし右辺値参照はx値として扱われることに注意してください。関数への右辺値参照は、名前が付けられているかどうかに関係なく、左辺値として扱われます。
#include <functional>
struct As
{
int i;
};
As&& f(){
return As();
}
int main()
{
f(); // The expression f() belongs to the xvalue category, because it refers to an unnamed rvalue reference to object.
As&& rr_a=As();
rr_a; // The expression rr_a belongs to the lvalue category, because it refers to a named rvalue reference to object.
std::ref(f); // The expression std::ref(f) belongs to the lvalue category, because it refers to an rvalue reference to function.
return 0;
}
prvalues
式Eがprvalueカテゴリに属するのは、Eがlvalueカテゴリにもxvalueカテゴリにも属していない場合のみです。
struct As
{
void f(){
this; // The expression this is a prvalue expression. Note, that the expression this is not a variable.
}
};
As f(){
return As();
}
int main()
{
f(); // The expression f() belongs to the prvalue category, because it belongs neither to the lvalue nor to the xvalue category.
return 0;
}
混合値のカテゴリー
さらに2つの重要な混合値カテゴリがあります。これらの値カテゴリは、右辺値と右辺値のカテゴリです。
右辺値
式Eは、Eがxvalueカテゴリまたはprvalueカテゴリに属している場合にのみ、rvalueカテゴリに属します。
この定義は、EがE YET外からアクセスできるようにするIDを持たないエンティティーを参照する場合にのみ、式Eが右辺値カテゴリーに属することを意味します。
輝かしい
式Eがglvalueカテゴリに属するのは、Eがlvalueカテゴリまたはxvalueカテゴリに属している場合のみです。
実践的なルール
スコット・マイヤーはしている出版さ左辺値から右辺値を区別するために親指の非常に便利なルールを。
- 式のアドレスを取得できる場合、式は左辺値です。
- 式のタイプが左辺値参照(たとえば、T&またはconst T&など)の場合、その式は左辺値です。
- それ以外の場合、式は右辺値です。概念的に(そして通常は実際には)、右辺値は、関数から返されたオブジェクトや暗黙の型変換によって作成されたオブジェクトなどの一時オブジェクトに対応します。ほとんどのリテラル値(たとえば、10と5.3)も右辺値です。