|
1 | 1 | --- |
2 | | -title: "Lvalues and Rvalues (Visual C++) | Microsoft Docs" |
| 2 | +title: "Value Categories: Lvalues and Rvalues (Visual C++) | Microsoft Docs" |
3 | 3 | ms.custom: "" |
4 | 4 | ms.date: "11/04/2016" |
5 | 5 | ms.reviewer: "" |
@@ -34,22 +34,18 @@ translation.priority.ht: |
34 | 34 | - "zh-tw" |
35 | 35 | --- |
36 | 36 | # Lvalues and Rvalues (Visual C++) |
37 | | -Every C++ expression is either an lvalue or an rvalue. An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (`const`) variables, are lvalues. An rvalue is a temporary value that does not persist beyond the expression that uses it. To better understand the difference between lvalues and rvalues, consider the following example: |
38 | | - |
39 | | -``` |
40 | | -// lvalues_and_rvalues1.cpp |
41 | | -// compile with: /EHsc |
42 | | -#include <iostream> |
43 | | -using namespace std; |
44 | | -int main() |
45 | | -{ |
46 | | - int x = 3 + 4; |
47 | | - cout << x << endl; |
48 | | -} |
49 | | -``` |
50 | | - |
51 | | - In this example, `x` is an lvalue because it persists beyond the expression that defines it. The expression `3 + 4` is an rvalue because it evaluates to a temporary value that does not persist beyond the expression that defines it. |
52 | | - |
| 37 | +Every C++ expression has a type, and belongs to a *value category*. The value categories are the basis for rules that compilers must follow when creating, copying, and moving temporary objects during expression evaluation. In C++17 the rules were restated to ensure that all compilers behave identically by not creating objects unless they are actually required. The new specified behavior is called "guaranteed copy elision." It helps to make your code more portable and efficient and eliminates the need to provide copy and move constructors for types that never use them. |
| 38 | + |
| 39 | + The C++17 standard defines value categories as follows: |
| 40 | + |
| 41 | +- A *glvalue* is an expression whose evaluation determines the identity of an object, bit-field, or function. |
| 42 | +- A *prvalue* is an expression whose evaluation initializes an object or a bit-field, or computes the value of the operand of an operator, as specified by the context in which it appears. |
| 43 | +- An *xvalue* is a glvalue that denotes an object or bit-field whose resources can be reused (usually because it is near the end of its lifetime). [ Example: Certain kinds of expressions involving rvalue references (8.3.2) yield xvalues, such as a call to a function whose return type is an rvalue reference or a cast to an rvalue reference type. ] |
| 44 | +- An *lvalue* is a glvalue that is not an xvalue. |
| 45 | +- An *rvalue* is a prvalue or an xvalue. |
| 46 | + |
| 47 | + Examples of lvalues include variables, including `const` variables, array elements, bit-fields, unions, and class members. Examples of rvalues include literals, function calls, and temporary objects that are created during expression evalution but accessible only by the compiler. |
| 48 | + |
53 | 49 | The following example demonstrates several correct and incorrect usages of lvalues and rvalues: |
54 | 50 |
|
55 | 51 | ``` |
@@ -79,6 +75,41 @@ int main() |
79 | 75 |
|
80 | 76 | > [!NOTE] |
81 | 77 | > The examples in this topic illustrate correct and incorrect usage when operators are not overloaded. By overloading operators, you can make an expression such as `j * 4` an lvalue. |
| 78 | +
|
| 79 | +The following example shows the new behavior for guaranteed copy elision. Note that construction from temporary objects succeeds in both cases despite the absence of a move constructor. |
| 80 | + |
| 81 | +```cpp |
| 82 | +#include <iostream> |
| 83 | +#include <string> |
| 84 | + |
| 85 | +using namespace std; |
| 86 | + |
| 87 | +struct S { |
| 88 | + S(int) { cout << "S(int)" << endl; } |
| 89 | + S(S&) = delete; |
| 90 | + S(S&&) = delete; // { cout << "move" << endl; } |
| 91 | + ///... |
| 92 | +}; |
| 93 | + |
| 94 | +S make_s() |
| 95 | +{ |
| 96 | + // Return value initialized directly at call site. |
| 97 | + // In Visual Studio 2015 this does not compile due to deleted move ctor. |
| 98 | + return S(42); |
| 99 | +} |
| 100 | + |
| 101 | + |
| 102 | +int main() |
| 103 | +{ |
| 104 | + auto nm = make_s(); |
| 105 | + S x4 = 5; // Construct from an rvalue. |
| 106 | +} |
| 107 | +``` |
| 108 | +The program produces this output: |
| 109 | +```output |
| 110 | +S(int) |
| 111 | +S(int) |
| 112 | +``` |
82 | 113 |
|
83 | 114 | The terms *lvalue* and *rvalue* are often used when you refer to object references. For more information about references, see [Lvalue Reference Declarator: &](../cpp/lvalue-reference-declarator-amp.md) and [Rvalue Reference Declarator: &&](../cpp/rvalue-reference-declarator-amp-amp.md). |
84 | 115 |
|
|
0 commit comments