- tmp/tmpc_mxg71i/{from.md → to.md} +89 -193
tmp/tmpc_mxg71i/{from.md → to.md}
RENAMED
|
@@ -8,44 +8,49 @@ 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 |
elision*, is permitted in the following circumstances (which may be
|
| 15 |
combined to eliminate multiple copies):
|
| 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
|
| 19 |
-
than a function parameter or a variable
|
| 20 |
-
*exception-declaration* of a *handler*
|
| 21 |
-
same type (ignoring cv-qualification) as
|
| 22 |
-
copy/move operation can be omitted by
|
| 23 |
-
object directly into the function call’s return
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
can be omitted by constructing the
|
| 30 |
-
exception object
|
| 31 |
-
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
-
Copy elision is
|
| 42 |
-
requiring a constant expression
|
| 43 |
-
initialization
|
| 44 |
|
| 45 |
-
[*Note 2*: Copy elision might
|
| 46 |
-
|
| 47 |
|
| 48 |
[*Example 1*:
|
| 49 |
|
| 50 |
``` cpp
|
| 51 |
class Thing {
|
|
@@ -66,58 +71,61 @@ struct A {
|
|
| 66 |
void *p;
|
| 67 |
constexpr A(): p(this) {}
|
| 68 |
};
|
| 69 |
|
| 70 |
constexpr A g() {
|
| 71 |
-
A
|
| 72 |
-
return
|
| 73 |
}
|
| 74 |
|
| 75 |
constexpr A a; // well-formed, a.p points to a
|
| 76 |
-
constexpr A b = g(); //
|
| 77 |
|
| 78 |
-
void
|
| 79 |
A c = g(); // well-formed, c.p may point to c or to an ephemeral temporary
|
| 80 |
}
|
| 81 |
```
|
| 82 |
|
| 83 |
-
Here the criteria for elision can eliminate the copying of the
|
| 84 |
-
|
| 85 |
-
which is the global object `t2`. Effectively, the
|
| 86 |
-
local object `t` can be viewed as directly
|
| 87 |
-
object `t2`, and that object’s destruction will
|
| 88 |
-
Adding a move constructor to `Thing` has the same
|
| 89 |
-
move construction from the
|
| 90 |
-
elided.
|
| 91 |
|
| 92 |
— *end example*]
|
| 93 |
|
| 94 |
-
|
| 95 |
-
|
|
|
|
|
|
|
| 96 |
|
| 97 |
-
- If the *expression* in a `return`
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
*parameter-declaration-clause* of the innermost enclosing
|
| 101 |
-
*lambda-expression*, or
|
| 102 |
-
- if the operand of a *throw-expression*
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
|
|
|
|
|
|
| 106 |
|
| 107 |
-
overload resolution to select the constructor for the copy
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
performed again, considering the object as an lvalue.
|
| 113 |
|
| 114 |
[*Note 3*: This two-stage overload resolution must be performed
|
| 115 |
regardless of whether copy elision will occur. It determines the
|
| 116 |
-
constructor to be called if elision is
|
| 117 |
-
|
| 118 |
-
elided. — *end note*]
|
| 119 |
|
| 120 |
[*Example 2*:
|
| 121 |
|
| 122 |
``` cpp
|
| 123 |
class Thing {
|
|
@@ -149,142 +157,30 @@ Weird g() {
|
|
| 149 |
}
|
| 150 |
```
|
| 151 |
|
| 152 |
— *end example*]
|
| 153 |
|
| 154 |
-
|
| 155 |
-
[basic.def.odr]: basic.md#basic.def.odr
|
| 156 |
-
[basic.life]: basic.md#basic.life
|
| 157 |
-
[basic.lookup]: basic.md#basic.lookup
|
| 158 |
-
[basic.lval]: basic.md#basic.lval
|
| 159 |
-
[basic.start.dynamic]: basic.md#basic.start.dynamic
|
| 160 |
-
[basic.start.static]: basic.md#basic.start.static
|
| 161 |
-
[basic.start.term]: basic.md#basic.start.term
|
| 162 |
-
[basic.stc.auto]: basic.md#basic.stc.auto
|
| 163 |
-
[basic.stc.dynamic]: basic.md#basic.stc.dynamic
|
| 164 |
-
[basic.stc.dynamic.deallocation]: basic.md#basic.stc.dynamic.deallocation
|
| 165 |
-
[basic.stc.static]: basic.md#basic.stc.static
|
| 166 |
-
[basic.stc.thread]: basic.md#basic.stc.thread
|
| 167 |
-
[basic.types]: basic.md#basic.types
|
| 168 |
-
[class]: class.md#class
|
| 169 |
-
[class.abstract]: class.md#class.abstract
|
| 170 |
-
[class.access]: class.md#class.access
|
| 171 |
-
[class.base.init]: #class.base.init
|
| 172 |
-
[class.cdtor]: #class.cdtor
|
| 173 |
-
[class.conv]: #class.conv
|
| 174 |
-
[class.conv.ctor]: #class.conv.ctor
|
| 175 |
-
[class.conv.fct]: #class.conv.fct
|
| 176 |
-
[class.copy]: #class.copy
|
| 177 |
-
[class.copy.assign]: #class.copy.assign
|
| 178 |
-
[class.copy.ctor]: #class.copy.ctor
|
| 179 |
-
[class.copy.elision]: #class.copy.elision
|
| 180 |
-
[class.ctor]: #class.ctor
|
| 181 |
-
[class.dtor]: #class.dtor
|
| 182 |
-
[class.expl.init]: #class.expl.init
|
| 183 |
-
[class.free]: #class.free
|
| 184 |
-
[class.friend]: class.md#class.friend
|
| 185 |
-
[class.inhctor.init]: #class.inhctor.init
|
| 186 |
-
[class.init]: #class.init
|
| 187 |
-
[class.mem]: class.md#class.mem
|
| 188 |
-
[class.member.lookup]: class.md#class.member.lookup
|
| 189 |
-
[class.mfct]: class.md#class.mfct
|
| 190 |
-
[class.mi]: class.md#class.mi
|
| 191 |
-
[class.qual]: basic.md#class.qual
|
| 192 |
-
[class.temporary]: #class.temporary
|
| 193 |
-
[class.union]: class.md#class.union
|
| 194 |
-
[class.union.anon]: class.md#class.union.anon
|
| 195 |
-
[class.virtual]: class.md#class.virtual
|
| 196 |
-
[conv]: conv.md#conv
|
| 197 |
-
[conv.array]: conv.md#conv.array
|
| 198 |
-
[conv.rval]: conv.md#conv.rval
|
| 199 |
-
[dcl.array]: dcl.md#dcl.array
|
| 200 |
-
[dcl.constexpr]: dcl.md#dcl.constexpr
|
| 201 |
-
[dcl.fct]: dcl.md#dcl.fct
|
| 202 |
-
[dcl.fct.def]: dcl.md#dcl.fct.def
|
| 203 |
-
[dcl.fct.def.delete]: dcl.md#dcl.fct.def.delete
|
| 204 |
-
[dcl.fct.default]: dcl.md#dcl.fct.default
|
| 205 |
-
[dcl.fct.spec]: dcl.md#dcl.fct.spec
|
| 206 |
-
[dcl.init]: dcl.md#dcl.init
|
| 207 |
-
[dcl.init.aggr]: dcl.md#dcl.init.aggr
|
| 208 |
-
[dcl.init.list]: dcl.md#dcl.init.list
|
| 209 |
-
[dcl.init.ref]: dcl.md#dcl.init.ref
|
| 210 |
-
[dcl.spec.auto]: dcl.md#dcl.spec.auto
|
| 211 |
-
[dcl.type.cv]: dcl.md#dcl.type.cv
|
| 212 |
-
[diff.special]: compatibility.md#diff.special
|
| 213 |
-
[except]: except.md#except
|
| 214 |
-
[except.ctor]: except.md#except.ctor
|
| 215 |
-
[except.handle]: except.md#except.handle
|
| 216 |
-
[except.spec]: except.md#except.spec
|
| 217 |
-
[except.throw]: except.md#except.throw
|
| 218 |
-
[expr]: expr.md#expr
|
| 219 |
-
[expr.ass]: expr.md#expr.ass
|
| 220 |
-
[expr.call]: expr.md#expr.call
|
| 221 |
-
[expr.cast]: expr.md#expr.cast
|
| 222 |
-
[expr.const]: expr.md#expr.const
|
| 223 |
-
[expr.const.cast]: expr.md#expr.const.cast
|
| 224 |
-
[expr.delete]: expr.md#expr.delete
|
| 225 |
-
[expr.dynamic.cast]: expr.md#expr.dynamic.cast
|
| 226 |
-
[expr.mptr.oper]: expr.md#expr.mptr.oper
|
| 227 |
-
[expr.new]: expr.md#expr.new
|
| 228 |
-
[expr.prim]: expr.md#expr.prim
|
| 229 |
-
[expr.prim.lambda.capture]: expr.md#expr.prim.lambda.capture
|
| 230 |
-
[expr.pseudo]: expr.md#expr.pseudo
|
| 231 |
-
[expr.ref]: expr.md#expr.ref
|
| 232 |
-
[expr.sizeof]: expr.md#expr.sizeof
|
| 233 |
-
[expr.static.cast]: expr.md#expr.static.cast
|
| 234 |
-
[expr.sub]: expr.md#expr.sub
|
| 235 |
-
[expr.throw]: expr.md#expr.throw
|
| 236 |
-
[expr.type.conv]: expr.md#expr.type.conv
|
| 237 |
-
[expr.typeid]: expr.md#expr.typeid
|
| 238 |
-
[expr.unary.op]: expr.md#expr.unary.op
|
| 239 |
-
[intro.execution]: intro.md#intro.execution
|
| 240 |
-
[intro.object]: intro.md#intro.object
|
| 241 |
-
[namespace.udecl]: dcl.md#namespace.udecl
|
| 242 |
-
[over.ass]: over.md#over.ass
|
| 243 |
-
[over.best.ics]: over.md#over.best.ics
|
| 244 |
-
[over.ics.ref]: over.md#over.ics.ref
|
| 245 |
-
[over.match]: over.md#over.match
|
| 246 |
-
[over.match.best]: over.md#over.match.best
|
| 247 |
-
[over.match.copy]: over.md#over.match.copy
|
| 248 |
-
[over.over]: over.md#over.over
|
| 249 |
-
[special]: #special
|
| 250 |
-
[stmt.dcl]: stmt.md#stmt.dcl
|
| 251 |
-
[stmt.return]: stmt.md#stmt.return
|
| 252 |
-
[temp.dep.type]: temp.md#temp.dep.type
|
| 253 |
-
[temp.variadic]: temp.md#temp.variadic
|
| 254 |
|
| 255 |
-
|
| 256 |
-
|
| 257 |
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
|
| 267 |
-
|
| 268 |
-
`operator` `delete` because [[expr.delete]] requires that in this
|
| 269 |
-
situation, the static type of the object to be deleted be the same
|
| 270 |
-
as its dynamic type.
|
| 271 |
|
| 272 |
-
[^4]: This implies that the reference parameter of the
|
| 273 |
-
implicitly-declared copy constructor cannot bind to a `volatile`
|
| 274 |
-
lvalue; see [[diff.special]].
|
| 275 |
-
|
| 276 |
-
[^5]: Because a template assignment operator or an assignment operator
|
| 277 |
-
taking an rvalue reference parameter is never a copy assignment
|
| 278 |
-
operator, the presence of such an assignment operator does not
|
| 279 |
-
suppress the implicit declaration of a copy assignment operator.
|
| 280 |
-
Such assignment operators participate in overload resolution with
|
| 281 |
-
other assignment operators, including copy assignment operators,
|
| 282 |
-
and, if selected, will be used to assign an object.
|
| 283 |
-
|
| 284 |
-
[^6]: This implies that the reference parameter of the
|
| 285 |
-
implicitly-declared copy assignment operator cannot bind to a
|
| 286 |
-
`volatile` lvalue; see [[diff.special]].
|
| 287 |
-
|
| 288 |
-
[^7]: Because only one object is destroyed instead of two, and one
|
| 289 |
-
copy/move constructor is not executed, there is still one object
|
| 290 |
-
destroyed for each one constructed.
|
|
|
|
| 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] This elision of copy/move operations, called *copy
|
| 14 |
elision*, is permitted in the following circumstances (which may be
|
| 15 |
combined to eliminate multiple copies):
|
| 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*
|
| 21 |
+
[[except.handle]]) with the same type (ignoring cv-qualification) as
|
| 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) whose scope does not extend beyond
|
| 28 |
+
the end of the innermost enclosing *try-block* (if there is one), the
|
| 29 |
+
copy/move operation can be omitted by constructing the object directly
|
| 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
|
| 36 |
+
- when the *exception-declaration* of an exception handler
|
| 37 |
+
[[except.pre]] declares an object of the same type (except for
|
| 38 |
+
cv-qualification) as the exception object [[except.throw]], the copy
|
| 39 |
+
operation can be omitted by treating the *exception-declaration* as an
|
| 40 |
+
alias for the exception object if the meaning of the program will be
|
| 41 |
+
unchanged except for the execution of constructors and destructors for
|
| 42 |
+
the object declared by the *exception-declaration*. \[*Note 1*: There
|
| 43 |
+
cannot be a move from the exception object because it is always an
|
| 44 |
+
lvalue. — *end note*]
|
| 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*: Copy elision might be performed if the same expression is
|
| 51 |
+
evaluated in another context. — *end note*]
|
| 52 |
|
| 53 |
[*Example 1*:
|
| 54 |
|
| 55 |
``` cpp
|
| 56 |
class Thing {
|
|
|
|
| 71 |
void *p;
|
| 72 |
constexpr A(): p(this) {}
|
| 73 |
};
|
| 74 |
|
| 75 |
constexpr A g() {
|
| 76 |
+
A loc;
|
| 77 |
+
return loc;
|
| 78 |
}
|
| 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 may point to c or to an ephemeral temporary
|
| 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 global object `t2`. Effectively, the
|
| 91 |
+
construction of the local object `t` can be viewed as directly
|
| 92 |
+
initializing the global object `t2`, and that object’s destruction will
|
| 93 |
+
occur at program exit. Adding a move constructor to `Thing` has the same
|
| 94 |
+
effect, but it is the move construction from the object with automatic
|
| 95 |
+
storage duration to `t2` that is elided.
|
| 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 {
|
|
|
|
| 157 |
}
|
| 158 |
```
|
| 159 |
|
| 160 |
— *end example*]
|
| 161 |
|
| 162 |
+
[*Example 3*:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
|
| 164 |
+
``` cpp
|
| 165 |
+
template<class T> void g(const T&);
|
| 166 |
|
| 167 |
+
template<class T> void f() {
|
| 168 |
+
T x;
|
| 169 |
+
try {
|
| 170 |
+
T y;
|
| 171 |
+
try { g(x); }
|
| 172 |
+
catch (...) {
|
| 173 |
+
if (/*...*/)
|
| 174 |
+
throw x; // does not move
|
| 175 |
+
throw y; // moves
|
| 176 |
+
}
|
| 177 |
+
g(y);
|
| 178 |
+
} catch(...) {
|
| 179 |
+
g(x);
|
| 180 |
+
g(y); // error: y is not in scope
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
```
|
| 184 |
|
| 185 |
+
— *end example*]
|
|
|
|
|
|
|
|
|
|
| 186 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|