tmp/tmpxmgy77oc/{from.md → to.md}
RENAMED
|
@@ -8,13 +8,15 @@ source and target of the omitted copy/move operation as simply two
|
|
| 8 |
different ways of referring to the same object. If the first parameter
|
| 9 |
of the selected constructor is an rvalue reference to the object’s type,
|
| 10 |
the destruction of that object occurs when the target would have been
|
| 11 |
destroyed; otherwise, the destruction occurs at the later of the times
|
| 12 |
when the two objects would have been destroyed without the
|
| 13 |
-
optimization.[^14]
|
| 14 |
-
|
| 15 |
-
|
|
|
|
|
|
|
| 16 |
|
| 17 |
- in a `return` statement in a function with a class return type, when
|
| 18 |
the *expression* is the name of a non-volatile object with automatic
|
| 19 |
storage duration (other than a function parameter or a variable
|
| 20 |
introduced by the *exception-declaration* of a *handler*
|
|
@@ -22,14 +24,14 @@ combined to eliminate multiple copies):
|
|
| 22 |
the function return type, the copy/move operation can be omitted by
|
| 23 |
constructing the object directly into the function call’s return
|
| 24 |
object
|
| 25 |
- in a *throw-expression* [[expr.throw]], when the operand is the name
|
| 26 |
of a non-volatile object with automatic storage duration (other than a
|
| 27 |
-
function or catch-clause parameter)
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
into the exception object
|
| 31 |
- in a coroutine [[dcl.fct.def.coroutine]], a copy of a coroutine
|
| 32 |
parameter can be omitted and references to that copy replaced with
|
| 33 |
references to the corresponding parameter if the meaning of the
|
| 34 |
program will be unchanged except for the execution of a constructor
|
| 35 |
and destructor for the parameter copy object
|
|
@@ -45,12 +47,12 @@ combined to eliminate multiple copies):
|
|
| 45 |
|
| 46 |
Copy elision is not permitted where an expression is evaluated in a
|
| 47 |
context requiring a constant expression [[expr.const]] and in constant
|
| 48 |
initialization [[basic.start.static]].
|
| 49 |
|
| 50 |
-
[*Note 2*:
|
| 51 |
-
evaluated in another context. — *end note*]
|
| 52 |
|
| 53 |
[*Example 1*:
|
| 54 |
|
| 55 |
``` cpp
|
| 56 |
class Thing {
|
|
@@ -79,54 +81,25 @@ constexpr A g() {
|
|
| 79 |
|
| 80 |
constexpr A a; // well-formed, a.p points to a
|
| 81 |
constexpr A b = g(); // error: b.p would be dangling[expr.const]
|
| 82 |
|
| 83 |
void h() {
|
| 84 |
-
A c = g(); // well-formed, c.p
|
| 85 |
}
|
| 86 |
```
|
| 87 |
|
| 88 |
Here the criteria for elision can eliminate the copying of the object
|
| 89 |
`t` with automatic storage duration into the result object for the
|
| 90 |
-
function call `f()`, which is the
|
| 91 |
-
construction of
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
|
| 97 |
— *end example*]
|
| 98 |
|
| 99 |
-
An *implicitly movable entity* is a variable of automatic storage
|
| 100 |
-
duration that is either a non-volatile object or an rvalue reference to
|
| 101 |
-
a non-volatile object type. In the following copy-initialization
|
| 102 |
-
contexts, a move operation might be used instead of a copy operation:
|
| 103 |
-
|
| 104 |
-
- If the *expression* in a `return` [[stmt.return]] or `co_return`
|
| 105 |
-
[[stmt.return.coroutine]] statement is a (possibly parenthesized)
|
| 106 |
-
*id-expression* that names an implicitly movable entity declared in
|
| 107 |
-
the body or *parameter-declaration-clause* of the innermost enclosing
|
| 108 |
-
function or *lambda-expression*, or
|
| 109 |
-
- if the operand of a *throw-expression* [[expr.throw]] is a (possibly
|
| 110 |
-
parenthesized) *id-expression* that names an implicitly movable entity
|
| 111 |
-
whose scope does not extend beyond the *compound-statement* of the
|
| 112 |
-
innermost *try-block* or *function-try-block* (if any) whose
|
| 113 |
-
*compound-statement* or *ctor-initializer* encloses the
|
| 114 |
-
*throw-expression*,
|
| 115 |
-
|
| 116 |
-
overload resolution to select the constructor for the copy or the
|
| 117 |
-
`return_value` overload to call is first performed as if the expression
|
| 118 |
-
or operand were an rvalue. If the first overload resolution fails or was
|
| 119 |
-
not performed, overload resolution is performed again, considering the
|
| 120 |
-
expression or operand as an lvalue.
|
| 121 |
-
|
| 122 |
-
[*Note 3*: This two-stage overload resolution must be performed
|
| 123 |
-
regardless of whether copy elision will occur. It determines the
|
| 124 |
-
constructor or the `return_value` overload to be called if elision is
|
| 125 |
-
not performed, and the selected constructor or `return_value` overload
|
| 126 |
-
must be accessible even if the call is elided. — *end note*]
|
| 127 |
-
|
| 128 |
[*Example 2*:
|
| 129 |
|
| 130 |
``` cpp
|
| 131 |
class Thing {
|
| 132 |
public:
|
|
@@ -138,24 +111,44 @@ private:
|
|
| 138 |
};
|
| 139 |
|
| 140 |
Thing f(bool b) {
|
| 141 |
Thing t;
|
| 142 |
if (b)
|
| 143 |
-
throw t; // OK
|
| 144 |
-
return t; // OK
|
| 145 |
}
|
| 146 |
|
| 147 |
-
Thing t2 = f(false); // OK
|
| 148 |
|
| 149 |
struct Weird {
|
| 150 |
Weird();
|
| 151 |
Weird(Weird&);
|
| 152 |
};
|
| 153 |
|
| 154 |
-
Weird g() {
|
| 155 |
-
Weird
|
| 156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
}
|
| 158 |
```
|
| 159 |
|
| 160 |
— *end example*]
|
| 161 |
|
|
|
|
| 8 |
different ways of referring to the same object. If the first parameter
|
| 9 |
of the selected constructor is an rvalue reference to the object’s type,
|
| 10 |
the destruction of that object occurs when the target would have been
|
| 11 |
destroyed; otherwise, the destruction occurs at the later of the times
|
| 12 |
when the two objects would have been destroyed without the
|
| 13 |
+
optimization.[^14]
|
| 14 |
+
|
| 15 |
+
This elision of copy/move operations, called *copy elision*, is
|
| 16 |
+
permitted in the following circumstances (which may be combined to
|
| 17 |
+
eliminate multiple copies):
|
| 18 |
|
| 19 |
- in a `return` statement in a function with a class return type, when
|
| 20 |
the *expression* is the name of a non-volatile object with automatic
|
| 21 |
storage duration (other than a function parameter or a variable
|
| 22 |
introduced by the *exception-declaration* of a *handler*
|
|
|
|
| 24 |
the function return type, the copy/move operation can be omitted by
|
| 25 |
constructing the object directly into the function call’s return
|
| 26 |
object
|
| 27 |
- in a *throw-expression* [[expr.throw]], when the operand is the name
|
| 28 |
of a non-volatile object with automatic storage duration (other than a
|
| 29 |
+
function or catch-clause parameter) that belongs to a scope that does
|
| 30 |
+
not contain the innermost enclosing *compound-statement* associated
|
| 31 |
+
with a *try-block* (if there is one), the copy/move operation can be
|
| 32 |
+
omitted by constructing the object directly into the exception object
|
| 33 |
- in a coroutine [[dcl.fct.def.coroutine]], a copy of a coroutine
|
| 34 |
parameter can be omitted and references to that copy replaced with
|
| 35 |
references to the corresponding parameter if the meaning of the
|
| 36 |
program will be unchanged except for the execution of a constructor
|
| 37 |
and destructor for the parameter copy object
|
|
|
|
| 47 |
|
| 48 |
Copy elision is not permitted where an expression is evaluated in a
|
| 49 |
context requiring a constant expression [[expr.const]] and in constant
|
| 50 |
initialization [[basic.start.static]].
|
| 51 |
|
| 52 |
+
[*Note 2*: It is possible that copy elision is performed if the same
|
| 53 |
+
expression is evaluated in another context. — *end note*]
|
| 54 |
|
| 55 |
[*Example 1*:
|
| 56 |
|
| 57 |
``` cpp
|
| 58 |
class Thing {
|
|
|
|
| 81 |
|
| 82 |
constexpr A a; // well-formed, a.p points to a
|
| 83 |
constexpr A b = g(); // error: b.p would be dangling[expr.const]
|
| 84 |
|
| 85 |
void h() {
|
| 86 |
+
A c = g(); // well-formed, c.p can point to c or be dangling
|
| 87 |
}
|
| 88 |
```
|
| 89 |
|
| 90 |
Here the criteria for elision can eliminate the copying of the object
|
| 91 |
`t` with automatic storage duration into the result object for the
|
| 92 |
+
function call `f()`, which is the non-local object `t2`. Effectively,
|
| 93 |
+
the construction of `t` can be viewed as directly initializing `t2`, and
|
| 94 |
+
that object’s destruction will occur at program exit. Adding a move
|
| 95 |
+
constructor to `Thing` has the same effect, but it is the move
|
| 96 |
+
construction from the object with automatic storage duration to `t2`
|
| 97 |
+
that is elided.
|
| 98 |
|
| 99 |
— *end example*]
|
| 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
[*Example 2*:
|
| 102 |
|
| 103 |
``` cpp
|
| 104 |
class Thing {
|
| 105 |
public:
|
|
|
|
| 111 |
};
|
| 112 |
|
| 113 |
Thing f(bool b) {
|
| 114 |
Thing t;
|
| 115 |
if (b)
|
| 116 |
+
throw t; // OK, Thing(Thing&&) used (or elided) to throw t
|
| 117 |
+
return t; // OK, Thing(Thing&&) used (or elided) to return t
|
| 118 |
}
|
| 119 |
|
| 120 |
+
Thing t2 = f(false); // OK, no extra copy/move performed, t2 constructed by call to f
|
| 121 |
|
| 122 |
struct Weird {
|
| 123 |
Weird();
|
| 124 |
Weird(Weird&);
|
| 125 |
};
|
| 126 |
|
| 127 |
+
Weird g(bool b) {
|
| 128 |
+
static Weird w1;
|
| 129 |
+
Weird w2;
|
| 130 |
+
if (b)
|
| 131 |
+
return w1; // OK, uses Weird(Weird&)
|
| 132 |
+
else
|
| 133 |
+
return w2; // error: w2 in this context is an xvalue
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
int& h(bool b, int i) {
|
| 137 |
+
static int s;
|
| 138 |
+
if (b)
|
| 139 |
+
return s; // OK
|
| 140 |
+
else
|
| 141 |
+
return i; // error: i is an xvalue
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
decltype(auto) h2(Thing t) {
|
| 145 |
+
return t; // OK, t is an xvalue and h2's return type is Thing
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
decltype(auto) h3(Thing t) {
|
| 149 |
+
return (t); // OK, (t) is an xvalue and h3's return type is Thing&&
|
| 150 |
}
|
| 151 |
```
|
| 152 |
|
| 153 |
— *end example*]
|
| 154 |
|