From Jason Turner

[class.copy.elision]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpblywn19a/{from.md → to.md} +290 -0
tmp/tmpblywn19a/{from.md → to.md} RENAMED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Copy/move elision <a id="class.copy.elision">[[class.copy.elision]]</a>
2
+
3
+ When certain criteria are met, an implementation is allowed to omit the
4
+ copy/move construction of a class object, even if the constructor
5
+ selected for the copy/move operation and/or the destructor for the
6
+ object have side effects. In such cases, the implementation treats the
7
+ 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 {
52
+ public:
53
+ Thing();
54
+ ~Thing();
55
+ Thing(const Thing&);
56
+ };
57
+
58
+ Thing f() {
59
+ Thing t;
60
+ return t;
61
+ }
62
+
63
+ Thing t2 = f();
64
+
65
+ 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 {
124
+ public:
125
+ Thing();
126
+ ~Thing();
127
+ Thing(Thing&&);
128
+ private:
129
+ Thing(const Thing&);
130
+ };
131
+
132
+ Thing f(bool b) {
133
+ Thing t;
134
+ if (b)
135
+ throw t; // OK: Thing(Thing&&) used (or elided) to throw t
136
+ return t; // OK: Thing(Thing&&) used (or elided) to return t
137
+ }
138
+
139
+ Thing t2 = f(false); // OK: no extra copy/move performed, t2 constructed by call to f
140
+
141
+ struct Weird {
142
+ Weird();
143
+ Weird(Weird&);
144
+ };
145
+
146
+ Weird g() {
147
+ Weird w;
148
+ return w; // OK: first overload resolution fails, second overload resolution selects Weird(Weird&)
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.