From Jason Turner

[class.copy.elision]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. 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.[^7] 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 automatic object (other
19
- than a function parameter or a variable introduced by the
20
- *exception-declaration* of a *handler* ([[except.handle]])) with the
21
- same type (ignoring cv-qualification) as the function return type, the
22
- copy/move operation can be omitted by constructing the automatic
23
- object directly into the function call’s return object
24
- - in a *throw-expression* ([[expr.throw]]), when the operand is the
25
- name of a non-volatile automatic object (other than a function or
26
- catch-clause parameter) whose scope does not extend beyond the end of
27
- the innermost enclosing *try-block* (if there is one), the copy/move
28
- operation from the operand to the exception object ([[except.throw]])
29
- can be omitted by constructing the automatic object directly into the
30
- exception object
31
- - when the *exception-declaration* of an exception handler (Clause 
32
- [[except]]) declares an object of the same type (except for
33
- cv-qualification) as the exception object ([[except.throw]]), the
34
- copy operation can be omitted by treating the *exception-declaration*
35
- as an alias for the exception object if the meaning of the program
36
- will be unchanged except for the execution of constructors and
37
- destructors for the object declared by the *exception-declaration*.
38
- \[*Note 1*: There cannot be a move from the exception object because
39
- it is always an lvalue. *end note*]
 
 
 
 
 
40
 
41
- Copy elision is required where an expression is evaluated in a context
42
- requiring a constant expression ([[expr.const]]) and in constant
43
- initialization ([[basic.start.static]]).
44
 
45
- [*Note 2*: Copy elision might not be performed if the same expression
46
- is evaluated in another context. — *end note*]
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 a;
72
- return a;
73
  }
74
 
75
  constexpr A a; // well-formed, a.p points to a
76
- constexpr A b = g(); // well-formed, b.p points to b
77
 
78
- void g() {
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 local
84
- automatic object `t` into the result object for the function call `f()`,
85
- which is the global object `t2`. Effectively, the construction of the
86
- local object `t` can be viewed as directly initializing the global
87
- object `t2`, and that object’s destruction will occur at program exit.
88
- Adding a move constructor to `Thing` has the same effect, but it is the
89
- move construction from the local automatic object to `t2` that is
90
- elided.
91
 
92
  — *end example*]
93
 
94
- In the following copy-initialization contexts, a move operation might be
95
- used instead of a copy operation:
 
 
96
 
97
- - If the *expression* in a `return` statement ([[stmt.return]]) is a
98
- (possibly parenthesized) *id-expression* that names an object with
99
- automatic storage duration declared in the body or
100
- *parameter-declaration-clause* of the innermost enclosing function or
101
- *lambda-expression*, or
102
- - if the operand of a *throw-expression* ([[expr.throw]]) is the name
103
- of a non-volatile automatic object (other than a function or
104
- catch-clause parameter) whose scope does not extend beyond the end of
105
- the innermost enclosing *try-block* (if there is one),
 
 
106
 
107
- overload resolution to select the constructor for the copy is first
108
- performed as if the object were designated by an rvalue. If the first
109
- overload resolution fails or was not performed, or if the type of the
110
- first parameter of the selected constructor is not an rvalue reference
111
- to the object’s type (possibly cv-qualified), overload resolution is
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 not performed, and the selected
117
- constructor must be accessible even if the call is
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
- <!-- Link reference definitions -->
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
- [^1]: The same rules apply to initialization of an `initializer_list`
256
- object ([[dcl.init.list]]) with its underlying temporary array.
257
 
258
- [^2]: These conversions are considered as standard conversions for the
259
- purposes of overload resolution ([[over.best.ics]],
260
- [[over.ics.ref]]) and therefore initialization ([[dcl.init]]) and
261
- explicit casts ([[expr.static.cast]]). A conversion to `void` does
262
- not invoke any conversion function ([[expr.static.cast]]). Even
263
- though never directly called to perform a conversion, such
264
- conversion functions can be declared and can potentially be reached
265
- through a call to a virtual conversion function in a base class.
 
 
 
 
 
 
 
 
 
266
 
267
- [^3]: A similar provision is not needed for the array version of
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