tmp/tmpiwc2m_1s/{from.md → to.md}
RENAMED
|
@@ -1,7 +1,9 @@
|
|
| 1 |
## Initialization <a id="class.init">[[class.init]]</a>
|
| 2 |
|
|
|
|
|
|
|
| 3 |
When no initializer is specified for an object of (possibly
|
| 4 |
cv-qualified) class type (or array thereof), or the initializer has the
|
| 5 |
form `()`, the object is initialized as specified in [[dcl.init]].
|
| 6 |
|
| 7 |
An object of class type (or array thereof) can be explicitly
|
|
@@ -61,11 +63,11 @@ complex v[6] = { 1, complex(1,2), complex(), 2 };
|
|
| 61 |
```
|
| 62 |
|
| 63 |
Here, `complex::complex(double)` is called for the initialization of
|
| 64 |
`v[0]` and `v[3]`, `complex::complex({}double, double)` is called for
|
| 65 |
the initialization of `v[1]`, `complex::complex()` is called for the
|
| 66 |
-
initialization `v[2]`, `v[4]`, and `v[5]`. For another example,
|
| 67 |
|
| 68 |
``` cpp
|
| 69 |
struct X {
|
| 70 |
int i;
|
| 71 |
float f;
|
|
@@ -118,20 +120,18 @@ mem-initializer:
|
|
| 118 |
mem-initializer-id:
|
| 119 |
class-or-decltype
|
| 120 |
identifier
|
| 121 |
```
|
| 122 |
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
scope, it is looked up in the scope containing the constructor’s
|
| 126 |
-
definition.
|
| 127 |
|
| 128 |
[*Note 1*: If the constructor’s class contains a member with the same
|
| 129 |
name as a direct or virtual base class of the class, a
|
| 130 |
*mem-initializer-id* naming the member or base class and composed of a
|
| 131 |
single identifier refers to the class member. A *mem-initializer-id* for
|
| 132 |
-
the hidden base class
|
| 133 |
name. — *end note*]
|
| 134 |
|
| 135 |
Unless the *mem-initializer-id* names the constructor’s class, a
|
| 136 |
non-static data member of the constructor’s class, or a direct or
|
| 137 |
virtual base of that class, the *mem-initializer* is ill-formed.
|
|
@@ -150,11 +150,11 @@ C::C(): global_A() { } // mem-initializer for base A
|
|
| 150 |
```
|
| 151 |
|
| 152 |
— *end example*]
|
| 153 |
|
| 154 |
If a *mem-initializer-id* is ambiguous because it designates both a
|
| 155 |
-
direct non-virtual base class and an
|
| 156 |
*mem-initializer* is ill-formed.
|
| 157 |
|
| 158 |
[*Example 2*:
|
| 159 |
|
| 160 |
``` cpp
|
|
@@ -238,14 +238,15 @@ struct A {
|
|
| 238 |
};
|
| 239 |
```
|
| 240 |
|
| 241 |
— *end example*]
|
| 242 |
|
| 243 |
-
In a non-delegating constructor
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
|
|
|
| 247 |
|
| 248 |
- if the entity is a non-static data member that has a default member
|
| 249 |
initializer [[class.mem]] and either
|
| 250 |
- the constructor’s class is a union [[class.union]], and no other
|
| 251 |
variant member of that union is designated by a *mem-initializer-id*
|
|
@@ -260,11 +261,11 @@ has no *ctor-initializer*), then
|
|
| 260 |
[[class.union.anon]], no initialization is performed;
|
| 261 |
- otherwise, the entity is default-initialized [[dcl.init]].
|
| 262 |
|
| 263 |
[*Note 3*: An abstract class [[class.abstract]] is never a most derived
|
| 264 |
class, thus its constructors never initialize virtual base classes,
|
| 265 |
-
therefore the corresponding *mem-initializer*s
|
| 266 |
omitted. — *end note*]
|
| 267 |
|
| 268 |
An attempt to initialize more than one non-static data member of a union
|
| 269 |
renders the program ill-formed.
|
| 270 |
|
|
@@ -286,14 +287,14 @@ struct B {
|
|
| 286 |
B(int);
|
| 287 |
};
|
| 288 |
|
| 289 |
struct C {
|
| 290 |
C() { } // initializes members as follows:
|
| 291 |
-
A a; // OK
|
| 292 |
const B b; // error: B has no default constructor
|
| 293 |
-
int i; // OK
|
| 294 |
-
int j = 5; // OK
|
| 295 |
};
|
| 296 |
```
|
| 297 |
|
| 298 |
— *end example*]
|
| 299 |
|
|
@@ -399,13 +400,14 @@ B b(3); // use V()
|
|
| 399 |
C c(4); // use V()
|
| 400 |
```
|
| 401 |
|
| 402 |
— *end example*]
|
| 403 |
|
| 404 |
-
|
| 405 |
-
*mem-initializer*
|
| 406 |
-
|
|
|
|
| 407 |
|
| 408 |
[*Example 10*:
|
| 409 |
|
| 410 |
``` cpp
|
| 411 |
class X {
|
|
@@ -424,15 +426,10 @@ of the constructor parameter `i`, initializes `X::i` with the value of
|
|
| 424 |
the constructor parameter `i`, and initializes `X::j` with the value of
|
| 425 |
`X::i`; this takes place each time an object of class `X` is created.
|
| 426 |
|
| 427 |
— *end example*]
|
| 428 |
|
| 429 |
-
[*Note 7*: Because the *mem-initializer* are evaluated in the scope of
|
| 430 |
-
the constructor, the `this` pointer can be used in the *expression-list*
|
| 431 |
-
of a *mem-initializer* to refer to the object being
|
| 432 |
-
initialized. — *end note*]
|
| 433 |
-
|
| 434 |
Member functions (including virtual member functions, [[class.virtual]])
|
| 435 |
can be called for an object under construction. Similarly, an object
|
| 436 |
under construction can be the operand of the `typeid` operator
|
| 437 |
[[expr.typeid]] or of a `dynamic_cast` [[expr.dynamic.cast]]. However,
|
| 438 |
if these operations are performed in a *ctor-initializer* (or in a
|
|
@@ -469,11 +466,11 @@ public:
|
|
| 469 |
};
|
| 470 |
```
|
| 471 |
|
| 472 |
— *end example*]
|
| 473 |
|
| 474 |
-
[*Note 8*: [[class.cdtor]] describes the
|
| 475 |
calls, `typeid` and `dynamic_cast`s during construction for the
|
| 476 |
well-defined cases; that is, describes the polymorphic behavior of an
|
| 477 |
object under construction. — *end note*]
|
| 478 |
|
| 479 |
A *mem-initializer* followed by an ellipsis is a pack expansion
|
|
@@ -523,28 +520,28 @@ struct D1 : B1 {
|
|
| 523 |
int x;
|
| 524 |
int y = get();
|
| 525 |
};
|
| 526 |
|
| 527 |
void test() {
|
| 528 |
-
D1 d(2, 3, 4); // OK
|
| 529 |
// then d.x is default-initialized (no initialization is performed),
|
| 530 |
// then d.y is initialized by calling get()
|
| 531 |
-
D1 e; // error: D1 has
|
| 532 |
}
|
| 533 |
|
| 534 |
struct D2 : B2 {
|
| 535 |
using B2::B2;
|
| 536 |
B1 b;
|
| 537 |
};
|
| 538 |
|
| 539 |
-
D2 f(1.0); // error: B1 has
|
| 540 |
|
| 541 |
struct W { W(int); };
|
| 542 |
struct X : virtual W { using W::W; X() = delete; };
|
| 543 |
struct Y : X { using X::X; };
|
| 544 |
struct Z : Y, virtual W { using Y::Y; };
|
| 545 |
-
Z z(0); // OK
|
| 546 |
|
| 547 |
template<class T> struct Log : T {
|
| 548 |
using T::T; // inherits all constructors from class T
|
| 549 |
~Log() { std::clog << "Destroying wrapper" << std::endl; }
|
| 550 |
};
|
|
@@ -580,18 +577,18 @@ struct D2 : V1, V2 {
|
|
| 580 |
using V1::V1;
|
| 581 |
using V2::V2;
|
| 582 |
};
|
| 583 |
|
| 584 |
D1 d1(0); // error: ambiguous
|
| 585 |
-
D2 d2(0); // OK
|
| 586 |
// then initializes the V1 and V2 base classes as if by a defaulted default constructor
|
| 587 |
|
| 588 |
struct M { M(); M(int); };
|
| 589 |
struct N : M { using M::M; };
|
| 590 |
struct O : M {};
|
| 591 |
struct P : N, O { using N::N; using O::O; };
|
| 592 |
-
P p(0); // OK
|
| 593 |
// use M() to initialize O's base class
|
| 594 |
```
|
| 595 |
|
| 596 |
— *end example*]
|
| 597 |
|
|
@@ -822,13 +819,15 @@ source and target of the omitted copy/move operation as simply two
|
|
| 822 |
different ways of referring to the same object. If the first parameter
|
| 823 |
of the selected constructor is an rvalue reference to the object’s type,
|
| 824 |
the destruction of that object occurs when the target would have been
|
| 825 |
destroyed; otherwise, the destruction occurs at the later of the times
|
| 826 |
when the two objects would have been destroyed without the
|
| 827 |
-
optimization.[^14]
|
| 828 |
-
|
| 829 |
-
|
|
|
|
|
|
|
| 830 |
|
| 831 |
- in a `return` statement in a function with a class return type, when
|
| 832 |
the *expression* is the name of a non-volatile object with automatic
|
| 833 |
storage duration (other than a function parameter or a variable
|
| 834 |
introduced by the *exception-declaration* of a *handler*
|
|
@@ -836,14 +835,14 @@ combined to eliminate multiple copies):
|
|
| 836 |
the function return type, the copy/move operation can be omitted by
|
| 837 |
constructing the object directly into the function call’s return
|
| 838 |
object
|
| 839 |
- in a *throw-expression* [[expr.throw]], when the operand is the name
|
| 840 |
of a non-volatile object with automatic storage duration (other than a
|
| 841 |
-
function or catch-clause parameter)
|
| 842 |
-
|
| 843 |
-
|
| 844 |
-
into the exception object
|
| 845 |
- in a coroutine [[dcl.fct.def.coroutine]], a copy of a coroutine
|
| 846 |
parameter can be omitted and references to that copy replaced with
|
| 847 |
references to the corresponding parameter if the meaning of the
|
| 848 |
program will be unchanged except for the execution of a constructor
|
| 849 |
and destructor for the parameter copy object
|
|
@@ -859,12 +858,12 @@ combined to eliminate multiple copies):
|
|
| 859 |
|
| 860 |
Copy elision is not permitted where an expression is evaluated in a
|
| 861 |
context requiring a constant expression [[expr.const]] and in constant
|
| 862 |
initialization [[basic.start.static]].
|
| 863 |
|
| 864 |
-
[*Note 2*:
|
| 865 |
-
evaluated in another context. — *end note*]
|
| 866 |
|
| 867 |
[*Example 1*:
|
| 868 |
|
| 869 |
``` cpp
|
| 870 |
class Thing {
|
|
@@ -893,54 +892,25 @@ constexpr A g() {
|
|
| 893 |
|
| 894 |
constexpr A a; // well-formed, a.p points to a
|
| 895 |
constexpr A b = g(); // error: b.p would be dangling[expr.const]
|
| 896 |
|
| 897 |
void h() {
|
| 898 |
-
A c = g(); // well-formed, c.p
|
| 899 |
}
|
| 900 |
```
|
| 901 |
|
| 902 |
Here the criteria for elision can eliminate the copying of the object
|
| 903 |
`t` with automatic storage duration into the result object for the
|
| 904 |
-
function call `f()`, which is the
|
| 905 |
-
construction of
|
| 906 |
-
|
| 907 |
-
|
| 908 |
-
|
| 909 |
-
|
| 910 |
|
| 911 |
— *end example*]
|
| 912 |
|
| 913 |
-
An *implicitly movable entity* is a variable of automatic storage
|
| 914 |
-
duration that is either a non-volatile object or an rvalue reference to
|
| 915 |
-
a non-volatile object type. In the following copy-initialization
|
| 916 |
-
contexts, a move operation might be used instead of a copy operation:
|
| 917 |
-
|
| 918 |
-
- If the *expression* in a `return` [[stmt.return]] or `co_return`
|
| 919 |
-
[[stmt.return.coroutine]] statement is a (possibly parenthesized)
|
| 920 |
-
*id-expression* that names an implicitly movable entity declared in
|
| 921 |
-
the body or *parameter-declaration-clause* of the innermost enclosing
|
| 922 |
-
function or *lambda-expression*, or
|
| 923 |
-
- if the operand of a *throw-expression* [[expr.throw]] is a (possibly
|
| 924 |
-
parenthesized) *id-expression* that names an implicitly movable entity
|
| 925 |
-
whose scope does not extend beyond the *compound-statement* of the
|
| 926 |
-
innermost *try-block* or *function-try-block* (if any) whose
|
| 927 |
-
*compound-statement* or *ctor-initializer* encloses the
|
| 928 |
-
*throw-expression*,
|
| 929 |
-
|
| 930 |
-
overload resolution to select the constructor for the copy or the
|
| 931 |
-
`return_value` overload to call is first performed as if the expression
|
| 932 |
-
or operand were an rvalue. If the first overload resolution fails or was
|
| 933 |
-
not performed, overload resolution is performed again, considering the
|
| 934 |
-
expression or operand as an lvalue.
|
| 935 |
-
|
| 936 |
-
[*Note 3*: This two-stage overload resolution must be performed
|
| 937 |
-
regardless of whether copy elision will occur. It determines the
|
| 938 |
-
constructor or the `return_value` overload to be called if elision is
|
| 939 |
-
not performed, and the selected constructor or `return_value` overload
|
| 940 |
-
must be accessible even if the call is elided. — *end note*]
|
| 941 |
-
|
| 942 |
[*Example 2*:
|
| 943 |
|
| 944 |
``` cpp
|
| 945 |
class Thing {
|
| 946 |
public:
|
|
@@ -952,24 +922,44 @@ private:
|
|
| 952 |
};
|
| 953 |
|
| 954 |
Thing f(bool b) {
|
| 955 |
Thing t;
|
| 956 |
if (b)
|
| 957 |
-
throw t; // OK
|
| 958 |
-
return t; // OK
|
| 959 |
}
|
| 960 |
|
| 961 |
-
Thing t2 = f(false); // OK
|
| 962 |
|
| 963 |
struct Weird {
|
| 964 |
Weird();
|
| 965 |
Weird(Weird&);
|
| 966 |
};
|
| 967 |
|
| 968 |
-
Weird g() {
|
| 969 |
-
Weird
|
| 970 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 971 |
}
|
| 972 |
```
|
| 973 |
|
| 974 |
— *end example*]
|
| 975 |
|
|
|
|
| 1 |
## Initialization <a id="class.init">[[class.init]]</a>
|
| 2 |
|
| 3 |
+
### General <a id="class.init.general">[[class.init.general]]</a>
|
| 4 |
+
|
| 5 |
When no initializer is specified for an object of (possibly
|
| 6 |
cv-qualified) class type (or array thereof), or the initializer has the
|
| 7 |
form `()`, the object is initialized as specified in [[dcl.init]].
|
| 8 |
|
| 9 |
An object of class type (or array thereof) can be explicitly
|
|
|
|
| 63 |
```
|
| 64 |
|
| 65 |
Here, `complex::complex(double)` is called for the initialization of
|
| 66 |
`v[0]` and `v[3]`, `complex::complex({}double, double)` is called for
|
| 67 |
the initialization of `v[1]`, `complex::complex()` is called for the
|
| 68 |
+
initialization of `v[2]`, `v[4]`, and `v[5]`. For another example,
|
| 69 |
|
| 70 |
``` cpp
|
| 71 |
struct X {
|
| 72 |
int i;
|
| 73 |
float f;
|
|
|
|
| 120 |
mem-initializer-id:
|
| 121 |
class-or-decltype
|
| 122 |
identifier
|
| 123 |
```
|
| 124 |
|
| 125 |
+
Lookup for an unqualified name in a *mem-initializer-id* ignores the
|
| 126 |
+
constructor’s function parameter scope.
|
|
|
|
|
|
|
| 127 |
|
| 128 |
[*Note 1*: If the constructor’s class contains a member with the same
|
| 129 |
name as a direct or virtual base class of the class, a
|
| 130 |
*mem-initializer-id* naming the member or base class and composed of a
|
| 131 |
single identifier refers to the class member. A *mem-initializer-id* for
|
| 132 |
+
the hidden base class can be specified using a qualified
|
| 133 |
name. — *end note*]
|
| 134 |
|
| 135 |
Unless the *mem-initializer-id* names the constructor’s class, a
|
| 136 |
non-static data member of the constructor’s class, or a direct or
|
| 137 |
virtual base of that class, the *mem-initializer* is ill-formed.
|
|
|
|
| 150 |
```
|
| 151 |
|
| 152 |
— *end example*]
|
| 153 |
|
| 154 |
If a *mem-initializer-id* is ambiguous because it designates both a
|
| 155 |
+
direct non-virtual base class and an indirect virtual base class, the
|
| 156 |
*mem-initializer* is ill-formed.
|
| 157 |
|
| 158 |
[*Example 2*:
|
| 159 |
|
| 160 |
``` cpp
|
|
|
|
| 238 |
};
|
| 239 |
```
|
| 240 |
|
| 241 |
— *end example*]
|
| 242 |
|
| 243 |
+
In a non-delegating constructor other than an implicitly-defined
|
| 244 |
+
copy/move constructor [[class.copy.ctor]], if a given potentially
|
| 245 |
+
constructed subobject is not designated by a *mem-initializer-id*
|
| 246 |
+
(including the case where there is no *mem-initializer-list* because the
|
| 247 |
+
constructor has no *ctor-initializer*), then
|
| 248 |
|
| 249 |
- if the entity is a non-static data member that has a default member
|
| 250 |
initializer [[class.mem]] and either
|
| 251 |
- the constructor’s class is a union [[class.union]], and no other
|
| 252 |
variant member of that union is designated by a *mem-initializer-id*
|
|
|
|
| 261 |
[[class.union.anon]], no initialization is performed;
|
| 262 |
- otherwise, the entity is default-initialized [[dcl.init]].
|
| 263 |
|
| 264 |
[*Note 3*: An abstract class [[class.abstract]] is never a most derived
|
| 265 |
class, thus its constructors never initialize virtual base classes,
|
| 266 |
+
therefore the corresponding *mem-initializer*s can be
|
| 267 |
omitted. — *end note*]
|
| 268 |
|
| 269 |
An attempt to initialize more than one non-static data member of a union
|
| 270 |
renders the program ill-formed.
|
| 271 |
|
|
|
|
| 287 |
B(int);
|
| 288 |
};
|
| 289 |
|
| 290 |
struct C {
|
| 291 |
C() { } // initializes members as follows:
|
| 292 |
+
A a; // OK, calls A::A()
|
| 293 |
const B b; // error: B has no default constructor
|
| 294 |
+
int i; // OK, i has indeterminate value
|
| 295 |
+
int j = 5; // OK, j has the value 5
|
| 296 |
};
|
| 297 |
```
|
| 298 |
|
| 299 |
— *end example*]
|
| 300 |
|
|
|
|
| 400 |
C c(4); // use V()
|
| 401 |
```
|
| 402 |
|
| 403 |
— *end example*]
|
| 404 |
|
| 405 |
+
[*Note 7*: The *expression-list* or *braced-init-list* of a
|
| 406 |
+
*mem-initializer* is in the function parameter scope of the constructor
|
| 407 |
+
and can use `this` to refer to the object being
|
| 408 |
+
initialized. — *end note*]
|
| 409 |
|
| 410 |
[*Example 10*:
|
| 411 |
|
| 412 |
``` cpp
|
| 413 |
class X {
|
|
|
|
| 426 |
the constructor parameter `i`, and initializes `X::j` with the value of
|
| 427 |
`X::i`; this takes place each time an object of class `X` is created.
|
| 428 |
|
| 429 |
— *end example*]
|
| 430 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
Member functions (including virtual member functions, [[class.virtual]])
|
| 432 |
can be called for an object under construction. Similarly, an object
|
| 433 |
under construction can be the operand of the `typeid` operator
|
| 434 |
[[expr.typeid]] or of a `dynamic_cast` [[expr.dynamic.cast]]. However,
|
| 435 |
if these operations are performed in a *ctor-initializer* (or in a
|
|
|
|
| 466 |
};
|
| 467 |
```
|
| 468 |
|
| 469 |
— *end example*]
|
| 470 |
|
| 471 |
+
[*Note 8*: [[class.cdtor]] describes the results of virtual function
|
| 472 |
calls, `typeid` and `dynamic_cast`s during construction for the
|
| 473 |
well-defined cases; that is, describes the polymorphic behavior of an
|
| 474 |
object under construction. — *end note*]
|
| 475 |
|
| 476 |
A *mem-initializer* followed by an ellipsis is a pack expansion
|
|
|
|
| 520 |
int x;
|
| 521 |
int y = get();
|
| 522 |
};
|
| 523 |
|
| 524 |
void test() {
|
| 525 |
+
D1 d(2, 3, 4); // OK, B1 is initialized by calling B1(2, 3, 4),
|
| 526 |
// then d.x is default-initialized (no initialization is performed),
|
| 527 |
// then d.y is initialized by calling get()
|
| 528 |
+
D1 e; // error: D1 has no default constructor
|
| 529 |
}
|
| 530 |
|
| 531 |
struct D2 : B2 {
|
| 532 |
using B2::B2;
|
| 533 |
B1 b;
|
| 534 |
};
|
| 535 |
|
| 536 |
+
D2 f(1.0); // error: B1 has no default constructor
|
| 537 |
|
| 538 |
struct W { W(int); };
|
| 539 |
struct X : virtual W { using W::W; X() = delete; };
|
| 540 |
struct Y : X { using X::X; };
|
| 541 |
struct Z : Y, virtual W { using Y::Y; };
|
| 542 |
+
Z z(0); // OK, initialization of Y does not invoke default constructor of X
|
| 543 |
|
| 544 |
template<class T> struct Log : T {
|
| 545 |
using T::T; // inherits all constructors from class T
|
| 546 |
~Log() { std::clog << "Destroying wrapper" << std::endl; }
|
| 547 |
};
|
|
|
|
| 577 |
using V1::V1;
|
| 578 |
using V2::V2;
|
| 579 |
};
|
| 580 |
|
| 581 |
D1 d1(0); // error: ambiguous
|
| 582 |
+
D2 d2(0); // OK, initializes virtual B base class, which initializes the A base class
|
| 583 |
// then initializes the V1 and V2 base classes as if by a defaulted default constructor
|
| 584 |
|
| 585 |
struct M { M(); M(int); };
|
| 586 |
struct N : M { using M::M; };
|
| 587 |
struct O : M {};
|
| 588 |
struct P : N, O { using N::N; using O::O; };
|
| 589 |
+
P p(0); // OK, use M(0) to initialize N's base class,
|
| 590 |
// use M() to initialize O's base class
|
| 591 |
```
|
| 592 |
|
| 593 |
— *end example*]
|
| 594 |
|
|
|
|
| 819 |
different ways of referring to the same object. If the first parameter
|
| 820 |
of the selected constructor is an rvalue reference to the object’s type,
|
| 821 |
the destruction of that object occurs when the target would have been
|
| 822 |
destroyed; otherwise, the destruction occurs at the later of the times
|
| 823 |
when the two objects would have been destroyed without the
|
| 824 |
+
optimization.[^14]
|
| 825 |
+
|
| 826 |
+
This elision of copy/move operations, called *copy elision*, is
|
| 827 |
+
permitted in the following circumstances (which may be combined to
|
| 828 |
+
eliminate multiple copies):
|
| 829 |
|
| 830 |
- in a `return` statement in a function with a class return type, when
|
| 831 |
the *expression* is the name of a non-volatile object with automatic
|
| 832 |
storage duration (other than a function parameter or a variable
|
| 833 |
introduced by the *exception-declaration* of a *handler*
|
|
|
|
| 835 |
the function return type, the copy/move operation can be omitted by
|
| 836 |
constructing the object directly into the function call’s return
|
| 837 |
object
|
| 838 |
- in a *throw-expression* [[expr.throw]], when the operand is the name
|
| 839 |
of a non-volatile object with automatic storage duration (other than a
|
| 840 |
+
function or catch-clause parameter) that belongs to a scope that does
|
| 841 |
+
not contain the innermost enclosing *compound-statement* associated
|
| 842 |
+
with a *try-block* (if there is one), the copy/move operation can be
|
| 843 |
+
omitted by constructing the object directly into the exception object
|
| 844 |
- in a coroutine [[dcl.fct.def.coroutine]], a copy of a coroutine
|
| 845 |
parameter can be omitted and references to that copy replaced with
|
| 846 |
references to the corresponding parameter if the meaning of the
|
| 847 |
program will be unchanged except for the execution of a constructor
|
| 848 |
and destructor for the parameter copy object
|
|
|
|
| 858 |
|
| 859 |
Copy elision is not permitted where an expression is evaluated in a
|
| 860 |
context requiring a constant expression [[expr.const]] and in constant
|
| 861 |
initialization [[basic.start.static]].
|
| 862 |
|
| 863 |
+
[*Note 2*: It is possible that copy elision is performed if the same
|
| 864 |
+
expression is evaluated in another context. — *end note*]
|
| 865 |
|
| 866 |
[*Example 1*:
|
| 867 |
|
| 868 |
``` cpp
|
| 869 |
class Thing {
|
|
|
|
| 892 |
|
| 893 |
constexpr A a; // well-formed, a.p points to a
|
| 894 |
constexpr A b = g(); // error: b.p would be dangling[expr.const]
|
| 895 |
|
| 896 |
void h() {
|
| 897 |
+
A c = g(); // well-formed, c.p can point to c or be dangling
|
| 898 |
}
|
| 899 |
```
|
| 900 |
|
| 901 |
Here the criteria for elision can eliminate the copying of the object
|
| 902 |
`t` with automatic storage duration into the result object for the
|
| 903 |
+
function call `f()`, which is the non-local object `t2`. Effectively,
|
| 904 |
+
the construction of `t` can be viewed as directly initializing `t2`, and
|
| 905 |
+
that object’s destruction will occur at program exit. Adding a move
|
| 906 |
+
constructor to `Thing` has the same effect, but it is the move
|
| 907 |
+
construction from the object with automatic storage duration to `t2`
|
| 908 |
+
that is elided.
|
| 909 |
|
| 910 |
— *end example*]
|
| 911 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 912 |
[*Example 2*:
|
| 913 |
|
| 914 |
``` cpp
|
| 915 |
class Thing {
|
| 916 |
public:
|
|
|
|
| 922 |
};
|
| 923 |
|
| 924 |
Thing f(bool b) {
|
| 925 |
Thing t;
|
| 926 |
if (b)
|
| 927 |
+
throw t; // OK, Thing(Thing&&) used (or elided) to throw t
|
| 928 |
+
return t; // OK, Thing(Thing&&) used (or elided) to return t
|
| 929 |
}
|
| 930 |
|
| 931 |
+
Thing t2 = f(false); // OK, no extra copy/move performed, t2 constructed by call to f
|
| 932 |
|
| 933 |
struct Weird {
|
| 934 |
Weird();
|
| 935 |
Weird(Weird&);
|
| 936 |
};
|
| 937 |
|
| 938 |
+
Weird g(bool b) {
|
| 939 |
+
static Weird w1;
|
| 940 |
+
Weird w2;
|
| 941 |
+
if (b)
|
| 942 |
+
return w1; // OK, uses Weird(Weird&)
|
| 943 |
+
else
|
| 944 |
+
return w2; // error: w2 in this context is an xvalue
|
| 945 |
+
}
|
| 946 |
+
|
| 947 |
+
int& h(bool b, int i) {
|
| 948 |
+
static int s;
|
| 949 |
+
if (b)
|
| 950 |
+
return s; // OK
|
| 951 |
+
else
|
| 952 |
+
return i; // error: i is an xvalue
|
| 953 |
+
}
|
| 954 |
+
|
| 955 |
+
decltype(auto) h2(Thing t) {
|
| 956 |
+
return t; // OK, t is an xvalue and h2's return type is Thing
|
| 957 |
+
}
|
| 958 |
+
|
| 959 |
+
decltype(auto) h3(Thing t) {
|
| 960 |
+
return (t); // OK, (t) is an xvalue and h3's return type is Thing&&
|
| 961 |
}
|
| 962 |
```
|
| 963 |
|
| 964 |
— *end example*]
|
| 965 |
|