値のカテゴリ、およびそれらへの参照Value categories, and references to them

このトピックでは、C++ に存在する値 (および値への参照) のさまざまなカテゴリについて説明します。This topic describes the various categories of values (and references to values) that exist in C++. 音が悪くなります左辺値rvalue、このトピックで条件のうちいない考えが。You will doubtless have heard of lvalues and rvalues, but you may not think of them in the terms that this topic presents. すぎるは、値の他の種類があります。And there are other kinds of values, too.

C++ では、すべての式では、このトピックで説明したカテゴリのいずれかに属している値を生成します。Every expression in C++ yields a value that belongs to one of the categories discussed in this topic. C++ 言語、その facilies、およびこれらの値のカテゴリ、およびそれらへの参照の適切な理解を必要とするルールの側面があります。There are aspects of the C++ language, its facilies, and rules, that demand a proper understanding of these value categories, and references to them. たとえば、値、値をコピーする、値の移動、および別の関数に値を転送のアドレスを取得します。For example, taking the address of a value, copying a value, moving a value, and forwarding a value on to another function. このトピックでは、すべての防御、これらの側面に移動しないが、それらの理解の基本的な情報を提供します。This topic doesn't go into all of those aspects in depth, but it provides foundational information for a solid understanding of them.

このトピックの情報は、id と movability [Stroustrup 2013] の 2 つの独立したプロパティで値のカテゴリの Stroustrup の分析の観点から囲まれています。The info in this topic is framed in terms of Stroustrup's analysis of value categories by the two independent properties of identity and movability [Stroustrup, 2013].

左辺値は id を持っていますAn lvalue has identity

これはどういうの値にidentityでしょうか。What does it mean for a value to have identity? 値のメモリ アドレスがある (またはを実行できます) し、値がある識別し、安全に使用します。If you have (or you can take) the memory address of a value and use it safely, then the value has identity. これにより、行うことができます比較より値の内容: 比較または id によって区別できます。That way, you can do more than compare the contents of values: you can compare or distinguish them by identity.

左辺値id を持ちます。An lvalue has identity. 今すぐ「左辺値」の"l"は、(ように、左側の hand 側を代入式の)、"left"の省略形を履歴にのみ関心のある問題です。It's now a matter of only historical interest that the "l" in "lvalue" is an abbreviation of "left" (as in, the left-hand-side of an assignment). C++ では、左辺値が左側に表示できるまたはを代入式の右側にします。In C++, an lvalue can appear on the left or on the right of an assignment. 「左辺値」の"l"し、実際に問題が解決しない理解もは何かを定義します。The "l" in "lvalues", then, doesn't actually help you to comprehend nor define what they are. Id を持つ値が左辺値と呼ばれるものであるかを理解するだけを指定する必要があります。You need only to understand that what we call an lvalue is a value that has identity.

左辺値である式の例に示します: 名前付きの変数または定数。または、参照を返す関数。Examples of expressions that are lvalues include: a named variable or constant; or a function that returns a reference. 式の例いない左辺値が含まれます: 一時的な; または値を返す関数。Examples of expressions that are not lvalues include: a temporary; or a function that returns by value.

int& get_by_ref() { ... }
int get_by_val() { ... }

int main()
{
    std::vector<byte> vec{ 99, 98, 97 };
    std::vector<byte>* addr1{ &vec }; // ok: vec is an lvalue.
    int* addr2{ &get_by_ref() }; // ok: get_by_ref() is an lvalue.

    int* addr3{ &(get_by_ref() + 1) }; // Error: get_by_ref() + 1 is not an lvalue.
    int* addr4{ &get_by_val() }; // Error: get_by_val() is not an lvalue.
}

ここで、左辺値が id を持っている場合は true。 ステートメントは、xvalues はそのためです。Now, while it's a true statement that lvalues have identity, so do xvalues. 他にどのようなことにしましょう、 xvalueはこのトピックで後述します。We'll go more into what an xvalue is later in this topic. ここでは、単に「左辺値を汎用化」の glvalue と呼ばれる値のカテゴリがあることに注意してください。For now, just be aware that there is a value category called glvalue, for "generalized lvalue". Glvalues のスーパー セットには、両方とも左辺値が含まれています (とも呼ばれます古典左辺値) と xvalues します。The superset of glvalues contains both lvalues (also known as classical lvalues) and xvalues. そのため、while true「を左辺値は、id を持って」は、この図のように、id を持つことの完全なセットが、glvalues のセット。So, while "an lvalue has identity" is true, the complete set of things that have identity is the set of glvalues, as shown in this illustration.

左辺値は id を持っています

右辺値は移動可能です。左辺値はありません。An rvalue is movable; an lvalue is not

Glvalues ではない値があります。But there are values that are not glvalues. したがって、ある値をできませんのメモリ アドレスを取得する (またはそれを有効にするのに依存することはできません)。Consequently, there are values that you can't obtain a memory address for (or you can't rely on it to be valid). 上記のコード例ではこのようないくつかの値を見ました。We saw some such values in the code example above. 欠点が聞こえます。This sounds like a disadvantage. 実際値の利点などができますが、移動から (これは一般的に安価な) ことではなく (これは通常高価な) からコピーします。But in fact the advantage of a value like that is that you can move from it (which is generally cheap), rather than copy from it (which is generally expensive). 値からの移行は場所に配置するために使用されなくを意味します。Moving from a value means that it's no longer in the place it used to be. そのため、使用場所にアクセスしようとしています。 は回避されます。So, trying to access it in the place it used to be is something to be avoided. タイミングの詳細については、方法値は、このトピックではスコープ外に移動します。A discussion of when and how to move a value is out of scope for this topic. このトピックでは、だけが移動可能な値と呼ばれることを知って、右辺値(または古典 rvalue)。For this topic, we just need to know that a value that is movable is known as an rvalue (or classical rvalue).

「右辺値」で"r"は、(ように、右、hand 側を代入式の)、"right"の省略形です。The "r" in "rvalue" is an abbreviation of "right" (as in, the right-hand-side of an assignment). ただし、右辺値、および割り当ての外部で、右辺値への参照を使用することができます。But you can use rvalues, and references to rvalues, outside of assignments. 「右辺値」で"r"に注目することはありません。The "r" in "rvalues", then, is not the thing to focus on. 右辺値と呼ばれるものが移動可能である値であることを理解するだけを指定する必要があります。You need only to understand that what we call an rvalue is a value that is movable.

この図のように、左辺値には逆に、移動可能なはありません。An lvalue, conversely, isn't movable, as shown in this illustration. 移動を左辺値の定義を無視は左辺値、引き続き、左辺値にアクセスすることができる非常に期待されるコードの予期しない問題があります。An lvalue that moved would defy the definition of lvalue, and it would be an unexpected problem for code that very reasonably expected to be able to continue to access the lvalue.

右辺値は移動可能です。左辺値はありません。

左辺の値を移動することはできません。You can't move an lvalue. あります移動できる glvalue (一連の id を持つもの) の一種—何をしていることがわかっている場合 (移動後にアクセスしないように注意するを含む)—xvalue です。But there is a kind of glvalue (the set of things with identity) that you can move—if you know what you're doing (including being careful not to access it after the move)—and that's the xvalue. このアイデアをもう 1 回、下の値のカテゴリの全体像に注目すると再度使用します。We'll revisit this idea one more time below, when we look at the complete picture of value categories.

右辺値参照、および参照バインディング規則Rvalue references, and reference-binding rules

このセクションでは、rvalue への参照の構文について説明します。This section introduces the syntax for a reference to an rvalue. 私たちは別のトピックに移動し、転送の大幅な処理を待機する必要がありますは右辺値参照を解決できる問題。We'll have to wait for another topic to go into a substantial treatment of moving and forwarding, but those are problems that are solved by rvalue references. 右辺値参照を見ると、前に、まず必要があります明確になるT&—ことした以前されて呼び出しだけ「参照」。Before we look at rvalue references, though, we first need to be clearer about T&—the thing we've formerly been calling just "a reference". 本当に"を (非定数) を左辺値参照されて"、これは、値を参照のユーザーが書き込むことができます。It's really "an lvalue (non-const) reference", which refers to an value to which the user of the reference can write.

template<typename T> T& get_by_lvalue_ref() { ... } // Get by lvalue (non-const) reference.
template<typename T> void set_by_lvalue_ref(T&) { ... } // Set by lvalue (non-const) reference.

左辺値参照は、右辺値ではなくに左辺値にバインドできます。An lvalue reference can bind to an lvalue, but not to an rvalue.

左辺値の const 参照が存在し、(T const&)、参照先オブジェクトに参照のユーザーことはできません書き込み (たとえば、定数)。Then there are lvalue const references (T const&), which refer to objects to which the user of the reference can't write (for example, a constant).

template<typename T> T const& get_by_lvalue_cref() { ... } // Get by lvalue const reference.
template<typename T> void set_by_lvalue_cref(T const&) { ... } // Set by lvalue const reference.

Const の左辺値参照には、左辺値または右辺値をバインドできます。An lvalue const reference can bind to an lvalue or to an rvalue.

型の rvalue への参照の構文は、Tとして書き込まれるT&&します。The syntax for a reference to an rvalue of type T is written as T&&. 移動可能な値を右辺値参照が参照—値を内容を後に使用した (たとえば、一時的な) を保持する必要はありません。An rvalue reference refers to a movable value—an value whose contents we don't need to preserve after we've used it (for example, a temporary). 全体のポイント以降から移動する (これにより変更)、値にバインドされて、右辺値参照constvolatile修飾子 (cv 修飾子のとも呼ばれます) は、右辺値参照に適用されません。Since the whole point is to move from (thereby modifying) the value bound to an rvalue reference, const and volatile qualifiers (also known as cv-qualifiers) don't apply to rvalue references.

template<typename T> T&& get_by_rvalue_ref() { ... } // Get by rvalue reference.
struct A { A(A&& other) { ... } }; // A move constructor takes an rvalue reference.

右辺値参照は、右辺値にバインドします。An rvalue reference binds to an rvalue. オーバー ロードの解決、右辺値の観点から実際には、希望より const の左辺値参照への右辺値参照にバインドします。In fact, in terms of overload resolution, an rvalue prefers to be bound to an rvalue reference than to an lvalue const reference. 参照しているため、ように、右辺値参照の値には (たとえば、移動コンストラクターのパラメーター) を保持するために不要と見なされますの内容が、右辺値参照が左辺値にバインドできません。But an rvalue reference can't bind to an lvalue because, as we've said, an rvalue reference refers to a value whose contents it's assumed we don't need to preserve (say, the parameter for a move constructor).

渡すこともできます右辺値渡しで引数が必要な場合、コピー コンストラクターを使用して (または移動の構築、右辺値が、xvalue 場合)。You can also pass an rvalue where a by-value argument is expected, via copy construction (or via move construction, if the rvalue is an xvalue).

Glvalue が identity です。prvalue はありません。A glvalue has identity; a prvalue does not

この段階では、id を持って何がわかっています。At this stage, we know what has identity. 移動可能な新機能とサポートされない内容がわかります。And we know what's movable and what isn't. いないまだという名前の値のセットですが、しないid が存在します。But we haven't yet named the set of values that don't have identity. セットと呼ばれること、 prvalue、または純粋な右辺値します。That set is known as the prvalue, or pure rvalue.

int& get_by_ref() { ... }
int get_by_val() { ... }

int main()
{
    int* addr3{ &(get_by_ref() + 1) }; // Error: get_by_ref() + 1 is a prvalue.
    int* addr4{ &get_by_val() }; // Error: get_by_val() is a prvalue.
}

左辺が identity です。prvalue はありません。

値のカテゴリの全体像The complete picture of value categories

情報と、1 つの大きな画像に上記の図を結合するだけのままです。It only remains to combine the info and illustrations above into a single, big picture.

値のカテゴリの全体像

glvalue (i)glvalue (i)

Glvalue (一般的な左辺値) は、id を持ちます。A glvalue (generalized lvalue) has identity.

左辺値 (は&!m)lvalue (i&!m)

左辺値 (glvalue の種類) は id を持つが、移動することはありません。An lvalue (a kind of glvalue) has identity, but isn't movable. これらは、通常の読み取り/書き込み値を渡して周囲参照または定数の参照または値のコピーは安価な場合です。These are typically read-write values that you pass around by reference or by const reference, or by value if copying is cheap. 左辺値は、右辺値参照にバインドできません。An lvalue can't be bound to an rvalue reference.

xvalue (は&m)xvalue (i&m)

(ある種の glvalue、ただしも、ある種の右辺値)、xvalue は id を持つ、移動することもできます。An xvalue (a kind of glvalue, but also a kind of rvalue) has identity, and is also movable. 転がって左辺値をコピーすることは高価であるために移動することが考えられますされ、その後アクセスしないように注意ができます。This might be an erstwhile lvalue that you've decided to move because copying is expensive, and you'll be careful not to access it afterward. 次に、xvalue に左辺を有効にする方法を示します。Here's how you can turn an lvalue into an xvalue.

struct A { ... };
A a; // a is an lvalue...
static_cast<A&&>(a); // ...but this expression is an xvalue.

上記のコード例で移動していない何もまだします。In the code example above, we haven't moved anything yet. 名前のない右辺値参照に左辺をキャストすることによって、xvalue 先ほど作成しました。We've just created an xvalue by casting an lvalue to an unnamed rvalue reference. 左辺値名によってまだ識別できます。の xvalue に今すぐ対応移動されるのです。It can still be identified by its lvalue name; but, as an xvalue, it is now capable of being moved. そのため、上の理由から、次のように、実際にどのような移動の別のトピックを待機する必要があります。The reasons for doing so, and what moving actually looks like, will have to wait for another topic. "X"で"xvalue"意味「エキスパート専用」に役立つ場合として考えることができます。But you can think of the "x" in "xvalue" as meaning "expert-only" if that helps. (右辺値の種類)、xvalue に左辺をキャストすることによって、値は、右辺値参照にバインドされていることになります。By casting an lvalue into an xvalue (a kind of rvalue), the value then becomes capable of being bound to an rvalue reference.

Xvalues の他の 2 つの例をここでは—名前のない右辺値参照を返す関数を呼び出すと、xvalue のメンバーにアクセスします。Here are two other examples of xvalues—calling a function that returns an unnamed rvalue reference, and accessing a member of an xvalue.

struct A { int m; };
A&& f();
f(); // This expression is an xvalue...
f().m; // ...and so is this.

prvalue (!は&m)prvalue (!i&m)

(純粋な右辺値はある種の右辺値) の prvalue では、id はありませんが、移動します。A prvalue (pure rvalue; a kind of rvalue) doesn't have identity, but is movable. これらの一時要素は通常、値、または、glvalue ではないその他の式の評価の結果によって関数の呼び出しの結果が返されますThese are typically temporaries, the result of calling a function that returns by value, or the result of evaluating any other expression that's not a glvalue,

右辺値 (m)rvalue (m)

右辺値は、移動可能です。An rvalue is movable. 右辺参照常に右辺値 (値を保持する必要がありますしない内容と見なされます) を参照します。An rvalue reference always refers to an rvalue (a value whose contents it's assumed we don't need to preserve).

右辺値参照自体を右辺値では。But, is an rvalue reference itself an rvalue? 名前のない(上記の xvalue コード例に示すもの) のような右辺値参照は、xvalue、はい、これは、右辺値です。An unnamed rvalue reference (like the ones shown in the xvalue code examples above) is an xvalue so, yes, it's an rvalue. 移動コンストラクターなど、右辺値参照を関数パラメーターにバインドするが優先されます。It prefers to be bound to an rvalue reference function parameter, such as that of a move constructor. 逆に、おそらく counter-intuitively)、右辺値参照は、名前を持つかどうかは、その名前で構成される式は左辺値です。Conversely (and perhaps counter-intuitively), if an rvalue reference has a name, then the expression consisting of that name is an lvalue. したがって、ことはできません右辺値参照パラメーターにバインドします。So it can't be bound to an rvalue reference parameter. それは簡単に行うことが—だけ再キャスト (xvalue、) の名前のない右辺値参照にします。But it's easy to make it do so—just cast it to an unnamed rvalue reference (an xvalue) again.

void foo(A&) { ... }
void foo(A&&) { ... }
void bar(A&& a) // a is a named rvalue reference; it's an lvalue.
{
    foo(a); // Calls foo(A&).
    foo(static_cast<A&&>(a)); // Calls foo(A&&).
}
A&& get_by_rvalue_ref() { ... } // This unnamed rvalue reference is an xvalue.

!&!m!i&!m

Id がないし、サポートされない移動可能な値の種類は、まだ説明していない 1 つの組み合わせです。The kind of value that doesn't have identity and isn't movable is the one combination that we haven't yet discussed. そのカテゴリには、C++ 言語で便利な考え方がないため、無視しました。But we can disregard it, because that category isn't a useful idea in the C++ language.

参照縮小規則Reference-collapsing rules

(左辺値参照は左辺値参照または右辺値参照を右辺値参照) の式に複数の like 参照は 1 つ別の出力をキャンセルします。Multiple like references in an expression (an lvalue reference to an lvalue reference, or an rvalue reference to an rvalue reference) cancel one another out.

  • A& & 折りたたまれますA&します。A& & collapses into A&.
  • A&& && 折りたたまれますA&&します。A&& && collapses into A&&.

左辺値参照を式内の参照とは異なり、複数を折りたたみます。Multiple unlike references in an expression collapse to an lvalue reference.

  • A& && 折りたたまれますA&します。A& && collapses into A&.
  • A&& & 折りたたまれますA&します。A&& & collapses into A&.

転送の参照Forwarding references

この最後のセクションでは、右辺値参照は、既に説明したようにのさまざまな概念と対照的です。 を転送参照します。This final section contrasts rvalue references, which we've already discussed, with the different concept of a forwarding reference.

void foo(A&& a) { ... }
  • A&& 前述したように、右辺値参照は、します。A&& is an rvalue reference, as we've seen. Const と揮発性は、右辺値参照に適用されません。Const and volatile don't apply to rvalue references.
  • foo 型の右辺値のみを受け入れるAします。foo accepts only rvalues of type A.
  • 理由の右辺値参照 (などA&&) 存在が渡される、一時的な (またはその他の右辺値) のケース用に最適化されたオーバー ロードを作成するようにします。The reason rvalue references (such as A&&) exist is so that you can author an overload that's optimized for the case of a temporary (or other rvalue) being passed.
template <typename _Ty> void bar(_Ty&& ty) { ... }
  • _Ty&& 転送参照します。_Ty&& is a forwarding reference. 渡すに応じてbar、型 _Ty const/非 const volatile/非 volatile とは無関係に可能性があります。Depending what you pass to bar, type _Ty could be const/non-const independently of volatile/non-volatile.
  • bar 任意の左辺値または右辺値の型を受け入れる _Tyします。bar accepts any lvalue or rvalue of type _Ty.
  • なる転送先の参照を左辺値を渡すと_Ty& &&、左辺値参照を解除する_Ty&します。Passing an lvalue causes the forwarding reference to become _Ty& &&, which collapses to the lvalue reference _Ty&.
  • なる転送先の参照を右辺値を渡すと_Ty&& &&、右辺値参照を解除する_Ty&&します。Passing an rvalue causes the forwarding reference to become _Ty&& &&, which collapses to the rvalue reference _Ty&&.
  • 参照を転送する理由 (など_Ty&&) 存在がいない最適化が何を渡すを実行して透過的かつ効率的に転送するようにします。The reason forwarding references (such as _Ty&&) exist is not for optimization, but to take what you pass to them and to forward it on transparently and efficiently. 書き込み、または密接に調査) ライブラリのコードの場合にのみ転送の参照が発生する可能性が高いしたら—コンストラクター引数では転送、factory 関数などです。You're likely to encounter a forwarding reference only if you write (or closely study) library code—for example, a factory function that forwards on constructor arguments.

SourcesSources

  • [Stroustrup、2013] B. Stroustrup:C++ プログラミング言語で、Fourth Edition。[Stroustrup, 2013] B. Stroustrup: The C++ Programming Language, Fourth Edition. Addison-Wesley.Addison-Wesley. 2013。2013.