857 lines
48 KiB
Markdown
857 lines
48 KiB
Markdown
[class.init]
|
||
|
||
# 11 Classes [[class]](./#class)
|
||
|
||
## 11.9 Initialization [class.init]
|
||
|
||
### [11.9.1](#general) General [[class.init.general]](class.init.general)
|
||
|
||
[1](#general-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5343)
|
||
|
||
When no initializer is specified for an object of (possibly
|
||
cv-qualified) class type (or array thereof), or the initializer has
|
||
the form(),
|
||
the object is initialized as specified in [[dcl.init]](dcl.init "9.5 Initializers")[.](#general-1.sentence-1)
|
||
|
||
[2](#general-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5350)
|
||
|
||
An object of class type (or array thereof) can be explicitly initialized;
|
||
see [[class.expl.init]](#class.expl.init "11.9.2 Explicit initialization") and [[class.base.init]](#class.base.init "11.9.3 Initializing bases and members")[.](#general-2.sentence-1)
|
||
|
||
[3](#general-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5354)
|
||
|
||
When an array of class objects is initialized
|
||
(either explicitly or implicitly) and the elements are initialized by constructor,
|
||
the constructor shall be called for each element of the array,
|
||
following the subscript order; see [[dcl.array]](dcl.array "9.3.4.5 Arrays")[.](#general-3.sentence-1)
|
||
|
||
[*Note [1](#general-note-1)*:
|
||
|
||
Destructors for the array elements are called in reverse order of their
|
||
construction[.](#general-3.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
### [11.9.2](#class.expl.init) Explicit initialization [[class.expl.init]](class.expl.init)
|
||
|
||
[1](#class.expl.init-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5369)
|
||
|
||
An object of class type can be initialized with a parenthesized[*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]"),
|
||
where the[*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") is construed as an argument list for a constructor
|
||
that is called to initialize the object[.](#class.expl.init-1.sentence-1)
|
||
|
||
Alternatively, a single[*assignment-expression*](expr.assign#nt:assignment-expression "7.6.19 Assignment and compound assignment operators [expr.assign]") can be specified as an[*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") using the= form of initialization[.](#class.expl.init-1.sentence-2)
|
||
|
||
Either direct-initialization semantics or copy-initialization semantics apply;
|
||
see [[dcl.init]](dcl.init "9.5 Initializers")[.](#class.expl.init-1.sentence-3)
|
||
|
||
[*Example [1](#class.expl.init-example-1)*: struct complex { complex();
|
||
complex(double);
|
||
complex(double,double);};
|
||
|
||
complex sqrt(complex,complex);
|
||
|
||
complex a(1); // initialized by calling complex(double) with argument 1 complex b = a; // initialized as a copy of a complex c = complex(1,2); // initialized by calling complex(double,double) with arguments 1 and 2 complex d = sqrt(b,c); // initialized by calling sqrt(complex,complex) with d as its result object complex e; // initialized by calling complex() complex f = 3; // initialized by calling complex(double) with argument 3 complex g = { 1, 2 }; // initialized by calling complex(double, double) with arguments 1 and 2 â *end example*]
|
||
|
||
[*Note [1](#class.expl.init-note-1)*:
|
||
|
||
Overloading of the assignment operator ([[over.assign]](over.assign "12.4.3.2 Simple assignment"))
|
||
has no effect on initialization[.](#class.expl.init-1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[2](#class.expl.init-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5410)
|
||
|
||
An object of class type can also be initialized by a[*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]")[.](#class.expl.init-2.sentence-1)
|
||
|
||
List-initialization semantics apply;
|
||
see [[dcl.init]](dcl.init "9.5 Initializers") and [[dcl.init.list]](dcl.init.list "9.5.5 List-initialization")[.](#class.expl.init-2.sentence-2)
|
||
|
||
[*Example [2](#class.expl.init-example-2)*: complex v[6] = { 1, complex(1,2), complex(), 2 };
|
||
|
||
Here,complex::complex(double) is called for the initialization ofv[0] andv[3],complex::complex(double, double) is called for the initialization ofv[1],complex::complex() is called for the initialization ofv[2],v[4],
|
||
andv[5][.](#class.expl.init-2.sentence-3)
|
||
|
||
For another example,
|
||
|
||
struct X {int i; float f;
|
||
complex c;} x = { 99, 88.8, 77.7 };
|
||
|
||
Here,x.i is initialized with 99,x.f is initialized with 88.8, andcomplex::complex(double) is called for the initialization ofx.c[.](#class.expl.init-2.sentence-5)
|
||
|
||
â *end example*]
|
||
|
||
[*Note [2](#class.expl.init-note-2)*:
|
||
|
||
Braces can be elided in the[*initializer-list*](dcl.init.general#nt:initializer-list "9.5.1 General [dcl.init.general]") for any aggregate, even if the aggregate has members of a class type with
|
||
user-defined type conversions; see [[dcl.init.aggr]](dcl.init.aggr "9.5.2 Aggregates")[.](#class.expl.init-2.sentence-6)
|
||
|
||
â *end note*]
|
||
|
||
[3](#class.expl.init-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5462)
|
||
|
||
[*Note [3](#class.expl.init-note-3)*:
|
||
|
||
IfT is a class type with no default constructor,
|
||
any initializing declaration of an object of typeT (or array thereof) is ill-formed if no[*initializer*](dcl.init.general#nt:initializer "9.5.1 General [dcl.init.general]") is explicitly specified (see [class.init] and [[dcl.init]](dcl.init "9.5 Initializers"))[.](#class.expl.init-3.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[4](#class.expl.init-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5474)
|
||
|
||
[*Note [4](#class.expl.init-note-4)*:
|
||
|
||
The order in which objects with static or thread storage duration
|
||
are initialized is described in [[basic.start.dynamic]](basic.start.dynamic "6.10.3.3 Dynamic initialization of non-block variables") and [[stmt.dcl]](stmt.dcl "8.10 Declaration statement")[.](#class.expl.init-4.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
### [11.9.3](#class.base.init) Initializing bases and members [[class.base.init]](class.base.init)
|
||
|
||
[1](#class.base.init-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5485)
|
||
|
||
In the definition of a constructor for a class,
|
||
initializers for direct and virtual base class subobjects and
|
||
non-static data members can be specified by a[*ctor-initializer*](#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]"),
|
||
which has the form
|
||
|
||
[ctor-initializer:](#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]")
|
||
: [*mem-initializer-list*](#nt:mem-initializer-list "11.9.3 Initializing bases and members [class.base.init]")
|
||
|
||
[mem-initializer-list:](#nt:mem-initializer-list "11.9.3 Initializing bases and members [class.base.init]")
|
||
[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") ...opt
|
||
[*mem-initializer-list*](#nt:mem-initializer-list "11.9.3 Initializing bases and members [class.base.init]") , [*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") ...opt
|
||
|
||
[mem-initializer:](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]")
|
||
[*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") ( [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]")opt )
|
||
[*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]")
|
||
|
||
[mem-initializer-id:](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]")
|
||
[*class-or-decltype*](class.derived.general#nt:class-or-decltype "11.7.1 General [class.derived.general]")
|
||
[*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")
|
||
|
||
[2](#class.base.init-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5514)
|
||
|
||
Lookup for an unqualified name in a [*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") ignores the constructor's function parameter scope[.](#class.base.init-2.sentence-1)
|
||
|
||
[*Note [1](#class.base.init-note-1)*:
|
||
|
||
If the constructor's class contains a member with the same name as a direct
|
||
or virtual base class of the class, a[*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") naming the member or base class and composed of a single identifier
|
||
refers to the class member[.](#class.base.init-2.sentence-2)
|
||
|
||
A[*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") for the hidden base class can be specified using a qualified name[.](#class.base.init-2.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
Unless the[*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") names the constructor's class,
|
||
a non-static data member of the constructor's class, or
|
||
a direct or virtual base of that class,
|
||
the[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") is ill-formed[.](#class.base.init-2.sentence-4)
|
||
|
||
[3](#class.base.init-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5536)
|
||
|
||
A[*mem-initializer-list*](#nt:mem-initializer-list "11.9.3 Initializing bases and members [class.base.init]") can initialize a base class using any [*class-or-decltype*](class.derived.general#nt:class-or-decltype "11.7.1 General [class.derived.general]") that denotes that base class type[.](#class.base.init-3.sentence-1)
|
||
|
||
[*Example [1](#class.base.init-example-1)*: struct A { A(); };typedef A global_A;struct B { };struct C: public A, public B { C(); };
|
||
C::C(): global_A() { } // mem-initializer for base A â *end example*]
|
||
|
||
[4](#class.base.init-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5550)
|
||
|
||
If a[*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") is ambiguous because it designates both a direct non-virtual base class and
|
||
an indirect virtual base class, the[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") is ill-formed[.](#class.base.init-4.sentence-1)
|
||
|
||
[*Example [2](#class.base.init-example-2)*: struct A { A(); };struct B: public virtual A { };struct C: public A, public B { C(); };
|
||
C::C(): A() { } // error: which A? â *end example*]
|
||
|
||
[5](#class.base.init-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5566)
|
||
|
||
A[*ctor-initializer*](#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]") may initialize a variant member of the
|
||
constructor's class[.](#class.base.init-5.sentence-1)
|
||
|
||
If a[*ctor-initializer*](#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]") specifies more than one[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") for the same member or for the same base class,
|
||
the[*ctor-initializer*](#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]") is ill-formed[.](#class.base.init-5.sentence-2)
|
||
|
||
[6](#class.base.init-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5580)
|
||
|
||
A [*mem-initializer-list*](#nt:mem-initializer-list "11.9.3 Initializing bases and members [class.base.init]") can delegate to another
|
||
constructor of the constructor's class using any[*class-or-decltype*](class.derived.general#nt:class-or-decltype "11.7.1 General [class.derived.general]") that denotes the constructor's class itself[.](#class.base.init-6.sentence-1)
|
||
|
||
If a[*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") designates the constructor's class,
|
||
it shall be the only [*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]"); the constructor
|
||
is a [*delegating constructor*](#def:constructor,delegating "11.9.3 Initializing bases and members [class.base.init]"), and the constructor selected by the[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") is the [*target constructor*](#def:constructor,target "11.9.3 Initializing bases and members [class.base.init]")[.](#class.base.init-6.sentence-2)
|
||
|
||
The target constructor is selected by overload resolution[.](#class.base.init-6.sentence-3)
|
||
|
||
Once the target constructor returns, the body of the delegating constructor
|
||
is executed[.](#class.base.init-6.sentence-4)
|
||
|
||
If a constructor delegates to itself directly or indirectly,
|
||
the program is ill-formed, no diagnostic required[.](#class.base.init-6.sentence-5)
|
||
|
||
[*Example [3](#class.base.init-example-3)*: struct C { C( int ) { } // #1: non-delegating constructor C(): C(42) { } // #2: delegates to #1 C( char c ) : C(42.0) { } // #3: ill-formed due to recursion with #4 C( double d ) : C('a') { } // #4: ill-formed due to recursion with #3}; â *end example*]
|
||
|
||
[7](#class.base.init-7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5603)
|
||
|
||
The[*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") or [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]") in a[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") is used to initialize the
|
||
designated subobject (or, in the case of a delegating constructor, the complete class object)
|
||
according to the initialization rules of [[dcl.init]](dcl.init "9.5 Initializers") for direct-initialization[.](#class.base.init-7.sentence-1)
|
||
|
||
[*Example [4](#class.base.init-example-4)*: struct B1 { B1(int); /* ... */ };struct B2 { B2(int); /* ... */ };struct D : B1, B2 { D(int);
|
||
B1 b; const int c;};
|
||
|
||
D::D(int a) : B2(a+1), B1(a+2), c(a+3), b(a+4) { /* ... */ } D d(10); â *end example*]
|
||
|
||
[*Note [2](#class.base.init-note-2)*:
|
||
|
||
The initialization
|
||
performed by each [*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") constitutes a full-expression ([[intro.execution]](intro.execution "6.10.1 Sequential execution"))[.](#class.base.init-7.sentence-2)
|
||
|
||
Any expression in
|
||
a[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") is evaluated as part of the full-expression that performs the initialization[.](#class.base.init-7.sentence-3)
|
||
|
||
â *end note*]
|
||
|
||
A [*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") where the [*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") denotes
|
||
a virtual base class is ignored during execution of a constructor of any class that is
|
||
not the most derived class[.](#class.base.init-7.sentence-4)
|
||
|
||
[8](#class.base.init-8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5641)
|
||
|
||
A temporary expression bound to a reference member in a [*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") is ill-formed[.](#class.base.init-8.sentence-1)
|
||
|
||
[*Example [5](#class.base.init-example-5)*: struct A { A() : v(42) { } // errorconst int& v;}; â *end example*]
|
||
|
||
[9](#class.base.init-9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5653)
|
||
|
||
In a non-delegating constructor
|
||
other than an implicitly-defined copy/move constructor ([[class.copy.ctor]](class.copy.ctor "11.4.5.3 Copy/move constructors")),
|
||
if a given potentially constructed subobject is not designated by a[*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") (including the case where there is no[*mem-initializer-list*](#nt:mem-initializer-list "11.9.3 Initializing bases and members [class.base.init]") because the constructor has no[*ctor-initializer*](#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]")),
|
||
then
|
||
|
||
- [(9.1)](#class.base.init-9.1)
|
||
|
||
if the entity is a non-static data member that has
|
||
a default member initializer ([[class.mem]](class.mem "11.4 Class members")) and either
|
||
* [(9.1.1)](#class.base.init-9.1.1)
|
||
|
||
the constructor's class is a union ([[class.union]](class.union "11.5 Unions")), and no other variant
|
||
member of that union is designated by a [*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]") or
|
||
|
||
* [(9.1.2)](#class.base.init-9.1.2)
|
||
|
||
the constructor's class is not a union, and, if the entity is a member of an
|
||
anonymous union, no other member of that union is designated by a[*mem-initializer-id*](#nt:mem-initializer-id "11.9.3 Initializing bases and members [class.base.init]"),
|
||
|
||
the entity is initialized from its default member initializer
|
||
as specified in [[dcl.init]](dcl.init "9.5 Initializers");
|
||
|
||
- [(9.2)](#class.base.init-9.2)
|
||
|
||
otherwise, if the entity is an anonymous union or a variant member ([[class.union.anon]](class.union.anon "11.5.2 Anonymous unions")), no initialization is performed;
|
||
|
||
- [(9.3)](#class.base.init-9.3)
|
||
|
||
otherwise, the entity is default-initialized ([[dcl.init]](dcl.init "9.5 Initializers"))[.](#class.base.init-9.sentence-1)
|
||
|
||
[*Note [3](#class.base.init-note-3)*:
|
||
|
||
An abstract class ([[class.abstract]](class.abstract "11.7.4 Abstract classes")) is never a most derived
|
||
class, thus its constructors never initialize virtual base classes, therefore the
|
||
corresponding [*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]")*s* can be omitted[.](#class.base.init-9.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
An attempt to initialize more than one non-static data member of a union renders the
|
||
program ill-formed[.](#class.base.init-9.sentence-3)
|
||
|
||
[*Note [4](#class.base.init-note-4)*:
|
||
|
||
After the call to a constructor for classX for an object with automatic or dynamic storage duration
|
||
has completed, if
|
||
the constructor was not invoked as part of value-initialization and
|
||
a member ofX is neither initialized nor
|
||
given a value
|
||
during execution of the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of the body of the constructor,
|
||
the member has an indeterminate or erroneous value ([[basic.indet]](basic.indet "6.8.5 Indeterminate and erroneous values"))[.](#class.base.init-9.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [6](#class.base.init-example-6)*: struct A { A();};
|
||
|
||
struct B { B(int);};
|
||
|
||
struct C { C() { } // initializes members as follows: A a; // OK, calls A::A()const B b; // error: B has no default constructorint i; // OK, i has indeterminate or erroneous valueint j = 5; // OK, j has the value 5}; â *end example*]
|
||
|
||
[10](#class.base.init-10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5724)
|
||
|
||
If a given non-static data member has both a default member initializer
|
||
and a [*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]"), the initialization specified by the[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") is performed, and the non-static data member's
|
||
default member initializer is ignored[.](#class.base.init-10.sentence-1)
|
||
|
||
[*Example [7](#class.base.init-example-7)*:
|
||
|
||
Givenstruct A {int i = /* some integer expression with side effects */ ;
|
||
A(int arg) : i(arg) { }// ...}; the A(int) constructor will simply initialize i to the value ofarg, and theside effects in i's default member initializer
|
||
will not take place[.](#class.base.init-10.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[11](#class.base.init-11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5748)
|
||
|
||
A temporary expression bound to a reference member from a
|
||
default member initializer is ill-formed[.](#class.base.init-11.sentence-1)
|
||
|
||
[*Example [8](#class.base.init-example-8)*: struct A { A() = default; // OK A(int v) : v(v) { } // OKconst int& v = 42; // OK};
|
||
A a1; // error: ill-formed binding of temporary to reference A a2(1); // OK, unfortunately â *end example*]
|
||
|
||
[12](#class.base.init-12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5763)
|
||
|
||
In a non-delegating constructor, the destructor for each potentially constructed
|
||
subobject of class type is potentially invoked ([[class.dtor]](class.dtor "11.4.7 Destructors"))[.](#class.base.init-12.sentence-1)
|
||
|
||
[*Note [5](#class.base.init-note-5)*:
|
||
|
||
This provision ensures that destructors can be called for fully-constructed
|
||
subobjects in case an exception is thrown ([[except.ctor]](except.ctor "14.3 Stack unwinding"))[.](#class.base.init-12.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[13](#class.base.init-13)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5771)
|
||
|
||
In a non-delegating constructor, initialization
|
||
proceeds in the following order:
|
||
|
||
- [(13.1)](#class.base.init-13.1)
|
||
|
||
First, and only for the constructor of the most derived class ([[intro.object]](intro.object "6.8.2 Object model")),
|
||
virtual base classes are initialized in the order they appear on a
|
||
depth-first left-to-right traversal of the directed acyclic graph of
|
||
base classes,
|
||
where âleft-to-rightâ is the order of appearance of the base classes
|
||
in the derived class[*base-specifier-list*](class.derived.general#nt:base-specifier-list "11.7.1 General [class.derived.general]")[.](#class.base.init-13.1.sentence-1)
|
||
|
||
- [(13.2)](#class.base.init-13.2)
|
||
|
||
Then, direct base classes are initialized in declaration order
|
||
as they appear in the[*base-specifier-list*](class.derived.general#nt:base-specifier-list "11.7.1 General [class.derived.general]") (regardless of the order of the[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]")*s*)[.](#class.base.init-13.2.sentence-1)
|
||
|
||
- [(13.3)](#class.base.init-13.3)
|
||
|
||
Then, non-static data members are initialized in the order
|
||
they were declared in the class definition
|
||
(again regardless of the order of the[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]")*s*)[.](#class.base.init-13.3.sentence-1)
|
||
|
||
- [(13.4)](#class.base.init-13.4)
|
||
|
||
Finally, the [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") of the constructor
|
||
body is executed[.](#class.base.init-13.4.sentence-1)
|
||
|
||
[*Note [6](#class.base.init-note-6)*:
|
||
|
||
The declaration order is mandated to ensure that base and member
|
||
subobjects are destroyed in the reverse order of initialization[.](#class.base.init-13.sentence-2)
|
||
|
||
â *end note*]
|
||
|
||
[14](#class.base.init-14)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5807)
|
||
|
||
[*Example [9](#class.base.init-example-9)*: struct V { V();
|
||
V(int);};
|
||
|
||
struct A : virtual V { A();
|
||
A(int);};
|
||
|
||
struct B : virtual V { B();
|
||
B(int);};
|
||
|
||
struct C : A, B, virtual V { C();
|
||
C(int);};
|
||
|
||
A::A(int i) : V(i) { /* ... */ } B::B(int i) { /* ... */ } C::C(int i) { /* ... */ } V v(1); // use V(int) A a(2); // use V(int) B b(3); // use V() C c(4); // use V() â *end example*]
|
||
|
||
[15](#class.base.init-15)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5841)
|
||
|
||
[*Note [7](#class.base.init-note-7)*:
|
||
|
||
The [*expression-list*](expr.post.general#nt:expression-list "7.6.1.1 General [expr.post.general]") or [*braced-init-list*](dcl.init.general#nt:braced-init-list "9.5.1 General [dcl.init.general]") of a [*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") is in the function parameter scope of the constructor
|
||
and can use this to refer to the object being initialized[.](#class.base.init-15.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[*Example [10](#class.base.init-example-10)*: class X {int a; int b; int i; int j;public:const int& r;
|
||
X(int i): r(a), b(i), i(i), j(this->i) { }};
|
||
|
||
initializesX::r to refer toX::a,
|
||
initializesX::b with the value of the constructor parameteri,
|
||
initializesX::i with the value of the constructor parameteri,
|
||
and initializesX::j with the value ofX::i;
|
||
this takes place each time an object of classX is created[.](#class.base.init-15.sentence-2)
|
||
|
||
â *end example*]
|
||
|
||
[16](#class.base.init-16)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5883)
|
||
|
||
Member functions (including virtual member functions, [[class.virtual]](class.virtual "11.7.3 Virtual functions")) can be
|
||
called for an object under construction or destruction[.](#class.base.init-16.sentence-1)
|
||
|
||
Similarly, an object under construction or destruction can be the operand of thetypeid operator ([[expr.typeid]](expr.typeid "7.6.1.8 Type identification")) or of adynamic_cast ([[expr.dynamic.cast]](expr.dynamic.cast "7.6.1.7 Dynamic cast"))[.](#class.base.init-16.sentence-2)
|
||
|
||
However, if these operations are performed
|
||
during evaluation of
|
||
|
||
- [(16.1)](#class.base.init-16.1)
|
||
|
||
a [*ctor-initializer*](#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]") (or in a function called directly or indirectly from a[*ctor-initializer*](#nt:ctor-initializer "11.9.3 Initializing bases and members [class.base.init]"))
|
||
before all the[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]")*s* for base classes have completed,
|
||
|
||
- [(16.2)](#class.base.init-16.2)
|
||
|
||
a precondition assertion of a constructor, or
|
||
|
||
- [(16.3)](#class.base.init-16.3)
|
||
|
||
a postcondition assertion of a destructor ([[dcl.contract.func]](dcl.contract.func "9.4.1 General")),
|
||
|
||
the program has undefined behavior[.](#class.base.init-16.sentence-3)
|
||
|
||
[*Example [11](#class.base.init-example-11)*: class A {public: A(int);};
|
||
|
||
class B : public A {int j;public:int f();
|
||
B() : A(f()), // undefined behavior: calls member function but base A not yet initialized j(f()) { } // well-defined: bases are all initialized};
|
||
|
||
class C {public: C(int);};
|
||
|
||
class D : public B, C {int i;public: D() : C(f()), // undefined behavior: calls member function but base C not yet initialized i(f()) { } // well-defined: bases are all initialized}; â *end example*]
|
||
|
||
[17](#class.base.init-17)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5936)
|
||
|
||
[*Note [8](#class.base.init-note-8)*:
|
||
|
||
[[class.cdtor]](#class.cdtor "11.9.5 Construction and destruction") describes the results of virtual function calls,typeid anddynamic_casts
|
||
during construction for the well-defined cases;
|
||
that is, describes the polymorphic behavior
|
||
of an object under construction[.](#class.base.init-17.sentence-1)
|
||
|
||
â *end note*]
|
||
|
||
[18](#class.base.init-18)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5947)
|
||
|
||
A [*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") followed by an ellipsis is
|
||
a pack expansion ([[temp.variadic]](temp.variadic "13.7.4 Variadic templates")) that initializes the base
|
||
classes specified by a pack expansion in the [*base-specifier-list*](class.derived.general#nt:base-specifier-list "11.7.1 General [class.derived.general]") for the class[.](#class.base.init-18.sentence-1)
|
||
|
||
[*Example [12](#class.base.init-example-12)*: template<class... Mixins>class X : public Mixins... {public: X(const Mixins&... mixins) : Mixins(mixins)... { }}; â *end example*]
|
||
|
||
### [11.9.4](#class.inhctor.init) Initialization by inherited constructor [[class.inhctor.init]](class.inhctor.init)
|
||
|
||
[1](#class.inhctor.init-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L5966)
|
||
|
||
When a constructor for type B is invoked
|
||
to initialize an object of a different type D (that is, when the constructor was inherited ([[namespace.udecl]](namespace.udecl "9.10 The using declaration"))),
|
||
initialization proceeds as if a defaulted default constructor
|
||
were used to initialize the D object and
|
||
each base class subobject from which the constructor was inherited,
|
||
except that the B subobject is initialized
|
||
by the inherited constructor
|
||
if the base class subobject were to be initialized
|
||
as part of the D object ([[class.base.init]](#class.base.init "11.9.3 Initializing bases and members"))[.](#class.inhctor.init-1.sentence-1)
|
||
|
||
The invocation of the inherited constructor,
|
||
including the evaluation of any arguments,
|
||
is omitted if the B subobject is not to be initialized
|
||
as part of the D object[.](#class.inhctor.init-1.sentence-2)
|
||
|
||
The complete initialization is considered to be a single function call;
|
||
in particular, unless omitted,
|
||
the initialization of the inherited constructor's parameters
|
||
is sequenced before the initialization of any part of the D object[.](#class.inhctor.init-1.sentence-3)
|
||
|
||
[*Example [1](#class.inhctor.init-example-1)*: struct B1 { B1(int, ...) { }};
|
||
|
||
struct B2 { B2(double) { }};
|
||
|
||
int get();
|
||
|
||
struct D1 : B1 {using B1::B1; // inherits B1(int, ...)int x; int y = get();};
|
||
|
||
void test() { D1 d(2, 3, 4); // OK, B1 is initialized by calling B1(2, 3, 4),// then d.x is default-initialized (no initialization is performed),// then d.y is initialized by calling get() D1 e; // error: D1 has no default constructor}struct D2 : B2 {using B2::B2;
|
||
B1 b;};
|
||
|
||
D2 f(1.0); // error: B1 has no default constructorstruct W { W(int); };struct X : virtual W { using W::W; X() = delete; };struct Y : X { using X::X; };struct Z : Y, virtual W { using Y::Y; };
|
||
Z z(0); // OK, initialization of Y does not invoke default constructor of Xtemplate<class T> struct Log : T {using T::T; // inherits all constructors from class T~Log() { std::clog << "Destroying wrapper" << std::endl; }};
|
||
|
||
Class template Log wraps any class and forwards all of its constructors,
|
||
while writing a message to the standard log
|
||
whenever an object of class Log is destroyed[.](#class.inhctor.init-1.sentence-4)
|
||
|
||
â *end example*]
|
||
|
||
[*Example [2](#class.inhctor.init-example-2)*: struct V { V() = default; V(int); };struct Q { Q(); };struct A : virtual V, Q {using V::V;
|
||
A() = delete;};int bar() { return 42; }struct B : A { B() : A(bar()) {} // OK};struct C : B {};void foo() { C c; } // bar is not invoked, because the V subobject is not initialized as part of B â *end example*]
|
||
|
||
[2](#class.inhctor.init-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6050)
|
||
|
||
If the constructor was inherited from multiple base class subobjects
|
||
of type B, the program is ill-formed[.](#class.inhctor.init-2.sentence-1)
|
||
|
||
[*Example [3](#class.inhctor.init-example-3)*: struct A { A(int); };struct B : A { using A::A; };
|
||
|
||
struct C1 : B { using B::B; };struct C2 : B { using B::B; };
|
||
|
||
struct D1 : C1, C2 {using C1::C1; using C2::C2;};
|
||
|
||
struct V1 : virtual B { using B::B; };struct V2 : virtual B { using B::B; };
|
||
|
||
struct D2 : V1, V2 {using V1::V1; using V2::V2;};
|
||
|
||
D1 d1(0); // error: ambiguous D2 d2(0); // OK, initializes virtual B base class, which initializes the A base class// then initializes the V1 and V2 base classes as if by a defaulted default constructorstruct M { M(); M(int); };struct N : M { using M::M; };struct O : M {};struct P : N, O { using N::N; using O::O; };
|
||
P p(0); // OK, use M(0) to initialize N's base class,// use M() to initialize O's base class â *end example*]
|
||
|
||
[3](#class.inhctor.init-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6087)
|
||
|
||
When an object is initialized by an inherited constructor,
|
||
initialization of the object is complete
|
||
when the initialization of all subobjects is complete[.](#class.inhctor.init-3.sentence-1)
|
||
|
||
### [11.9.5](#class.cdtor) Construction and destruction [[class.cdtor]](class.cdtor)
|
||
|
||
[1](#class.cdtor-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6097)
|
||
|
||
For an object with a non-trivial constructor, referring to any non-static member
|
||
or base class of the object before the constructor begins execution results in
|
||
undefined behavior[.](#class.cdtor-1.sentence-1)
|
||
|
||
For an object with a non-trivial destructor, referring to
|
||
any non-static member or base class of the object after the destructor finishes
|
||
execution results in undefined behavior[.](#class.cdtor-1.sentence-2)
|
||
|
||
[*Example [1](#class.cdtor-example-1)*: struct X { int i; };struct Y : X { Y(); }; // non-trivialstruct A { int a; };struct B : public A { int j; Y y; }; // non-trivialextern B bobj;
|
||
B* pb = &bobj; // OKint* p1 = &bobj.a; // undefined behavior: refers to base class memberint* p2 = &bobj.y.i; // undefined behavior: refers to member's member A* pa = &bobj; // undefined behavior: upcast to a base class type B bobj; // definition of bobjextern X xobj;int* p3 = &xobj.i; // OK, all constructors of X are trivial X xobj;
|
||
|
||
For another example,struct W { int j; };struct X : public virtual W { };struct Y {int* p;
|
||
X x;
|
||
Y() : p(&x.j) { // undefined, x is not yet constructed}};
|
||
|
||
â *end example*]
|
||
|
||
[2](#class.cdtor-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6137)
|
||
|
||
During the construction of an object,
|
||
if the value of any of its subobjects
|
||
or any element of its object representation
|
||
is accessed through a glvalue that is not obtained, directly or indirectly, from
|
||
the constructor'sthis pointer, the value thus obtained is unspecified[.](#class.cdtor-2.sentence-1)
|
||
|
||
[*Example [2](#class.cdtor-example-2)*: struct C;void no_opt(C*);
|
||
|
||
struct C {int c;
|
||
C() : c(0) { no_opt(this); }};
|
||
|
||
const C cobj;
|
||
|
||
void no_opt(C* cptr) {int i = cobj.c * 100; // value of cobj.c is unspecified cptr->c = 1;
|
||
cout << cobj.c * 100 // value of cobj.c is unspecified<< '\n';}extern struct D d;struct D { D(int a) : a(a), b(d.a) {}int a, b;};
|
||
D d = D(1); // value of d.b is unspecified â *end example*]
|
||
|
||
[3](#class.cdtor-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6173)
|
||
|
||
To explicitly or implicitly convert a pointer (a glvalue) referring to
|
||
an object of classX to a pointer (reference) to a direct or indirect base classB ofX,
|
||
the construction ofX and the construction of all of its direct or indirect bases that directly or
|
||
indirectly derive fromB shall have started and the destruction of these classes shall not have
|
||
completed, otherwise the conversion results in undefined behavior[.](#class.cdtor-3.sentence-1)
|
||
|
||
To form a pointer to (or access the value of) a direct non-static member of
|
||
an objectobj,
|
||
the construction ofobj shall have started and its destruction shall not have completed,
|
||
otherwise the computation of the pointer value (or accessing the member
|
||
value) results in undefined behavior[.](#class.cdtor-3.sentence-2)
|
||
|
||
[*Example [3](#class.cdtor-example-3)*: struct A { };struct B : virtual A { };struct C : B { };struct D : virtual A { D(A*); };struct X { X(A*); };
|
||
|
||
struct E : C, D, X { E() : D(this), // undefined behavior: upcast from E* to A* might use path E* â D* â A*// but D is not constructed// âD((C*)this)'' would be defined: E* â C* is defined because E() has started,// and C* â A* is defined because C is fully constructed X(this) {} // defined: upon construction of X, C/B/D/A sublattice is fully constructed}; â *end example*]
|
||
|
||
[4](#class.cdtor-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6218)
|
||
|
||
Member functions, including virtual functions ([[class.virtual]](class.virtual "11.7.3 Virtual functions")), can be called
|
||
during construction or destruction ([[class.base.init]](#class.base.init "11.9.3 Initializing bases and members"))[.](#class.cdtor-4.sentence-1)
|
||
|
||
When a virtual function is called directly or indirectly from a constructor
|
||
or from a destructor,
|
||
including during the construction or destruction of the class's non-static data
|
||
members,
|
||
or during the evaluation of
|
||
a postcondition assertion of a constructor or
|
||
a precondition assertion of a destructor ([[dcl.contract.func]](dcl.contract.func "9.4.1 General")),
|
||
and the object to which the call applies is the object (call it x) under construction or
|
||
destruction,
|
||
the function called is the
|
||
final overrider in the constructor's or destructor's class and not one
|
||
overriding it in a more-derived class[.](#class.cdtor-4.sentence-2)
|
||
|
||
If the virtual function call uses an explicit class member access ([[expr.ref]](expr.ref "7.6.1.5 Class member access"))
|
||
and the object expression refers to
|
||
the complete object of x or one of that object's base class subobjects
|
||
but not x or one of its base class subobjects, the behavior
|
||
is undefined[.](#class.cdtor-4.sentence-3)
|
||
|
||
[*Example [4](#class.cdtor-example-4)*: struct V {virtual void f(); virtual void g();};
|
||
|
||
struct A : virtual V {virtual void f();};
|
||
|
||
struct B : virtual V {virtual void g();
|
||
B(V*, A*);};
|
||
|
||
struct D : A, B {virtual void f(); virtual void g();
|
||
D() : B((A*)this, this) { }};
|
||
|
||
B::B(V* v, A* a) { f(); // calls V::f, not A::f g(); // calls B::g, not D::g v->g(); // v is base of B, the call is well-defined, calls B::g a->f(); // undefined behavior: a's type not a base of B} â *end example*]
|
||
|
||
[5](#class.cdtor-5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6273)
|
||
|
||
Thetypeid operator ([[expr.typeid]](expr.typeid "7.6.1.8 Type identification")) can be used during construction or destruction ([[class.base.init]](#class.base.init "11.9.3 Initializing bases and members"))[.](#class.cdtor-5.sentence-1)
|
||
|
||
Whentypeid is used in a constructor (including the[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") or default member initializer ([[class.mem]](class.mem "11.4 Class members"))
|
||
for a non-static data member)
|
||
or in a destructor, or used in a function called (directly or indirectly) from
|
||
a constructor or destructor, if the operand oftypeid refers to the object under construction or destruction,typeid yields thestd::type_info object representing the constructor or destructor's class[.](#class.cdtor-5.sentence-2)
|
||
|
||
If the operand oftypeid refers to the object under construction or destruction and the static type of
|
||
the operand is neither the constructor or destructor's class nor one of its
|
||
bases, the behavior is undefined[.](#class.cdtor-5.sentence-3)
|
||
|
||
[6](#class.cdtor-6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6300)
|
||
|
||
dynamic_casts ([[expr.dynamic.cast]](expr.dynamic.cast "7.6.1.7 Dynamic cast")) can be used during construction
|
||
or destruction ([[class.base.init]](#class.base.init "11.9.3 Initializing bases and members"))[.](#class.cdtor-6.sentence-1)
|
||
|
||
When adynamic_cast is used in a constructor (including the[*mem-initializer*](#nt:mem-initializer "11.9.3 Initializing bases and members [class.base.init]") or default member initializer
|
||
for a non-static data member)
|
||
or in a destructor, or used in a function called (directly or indirectly) from
|
||
a constructor or destructor, if the operand of thedynamic_cast refers to the object under construction or destruction, this object is
|
||
considered to be a most derived object that has the type of the constructor or
|
||
destructor's class[.](#class.cdtor-6.sentence-2)
|
||
|
||
If the operand of thedynamic_cast refers to the object under construction or destruction and the static type of
|
||
the operand is not a pointer to or object of the constructor or destructor's
|
||
own class or one of its bases, thedynamic_cast results in undefined behavior[.](#class.cdtor-6.sentence-3)
|
||
|
||
[*Example [5](#class.cdtor-example-5)*: struct V {virtual void f();};
|
||
|
||
struct A : virtual V { };
|
||
|
||
struct B : virtual V { B(V*, A*);};
|
||
|
||
struct D : A, B { D() : B((A*)this, this) { }};
|
||
|
||
B::B(V* v, A* a) {typeid(*this); // type_info for Btypeid(*v); // well-defined: *v has type V, a base of B yields type_info for Btypeid(*a); // undefined behavior: type A not a base of Bdynamic_cast<B*>(v); // well-defined: v of type V*, V base of B results in B*dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of B} â *end example*]
|
||
|
||
### [11.9.6](#class.copy.elision) Copy/move elision [[class.copy.elision]](class.copy.elision)
|
||
|
||
[1](#class.copy.elision-1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6354)
|
||
|
||
When certain criteria are met, an implementation is
|
||
allowed to omit the creation of a class object from
|
||
a source object of the same type (ignoring cv-qualification),
|
||
even if the selected constructor and/or the
|
||
destructor for the object haveside effects[.](#class.copy.elision-1.sentence-1)
|
||
|
||
In such cases, the
|
||
implementation treats the source and target of the
|
||
omitted initialization as simply two different ways of
|
||
referring to the same object[.](#class.copy.elision-1.sentence-2)
|
||
|
||
If the first parameter of the
|
||
selected constructor is an rvalue reference to the object's type,
|
||
the destruction of that object occurs when the target would have been destroyed;
|
||
otherwise, the destruction occurs at the later of the times when the
|
||
two objects would have been destroyed without the
|
||
optimization[.](#class.copy.elision-1.sentence-3)
|
||
|
||
[*Note [1](#class.copy.elision-note-1)*:
|
||
|
||
Because only one object is destroyed instead of two,
|
||
and the creation of one object is omitted,
|
||
there is still one object destroyed for each one constructed[.](#class.copy.elision-1.sentence-4)
|
||
|
||
â *end note*]
|
||
|
||
This elision of object creation, called[*copy elision*](#def:copy_elision),
|
||
is permitted in the
|
||
following circumstances (which may be combined to
|
||
eliminate multiple copies):
|
||
|
||
- [(1.1)](#class.copy.elision-1.1)
|
||
|
||
in a return statement ([[stmt.return]](stmt.return "8.8.4 The return statement")) in
|
||
a function with a class return type,
|
||
when the [*expression*](expr.comma#nt:expression "7.6.20 Comma operator [expr.comma]") is the name of a non-volatile
|
||
object o with automatic storage duration (other than a function parameter or a variable
|
||
introduced by the [*exception-declaration*](except.pre#nt:exception-declaration "14.1 Preamble [except.pre]") of a[*handler*](except.pre#nt:handler "14.1 Preamble [except.pre]") ([[except.handle]](except.handle "14.4 Handling an exception"))),
|
||
the copy-initialization of the result object can be
|
||
omitted by constructing o directly
|
||
into the function call's result object;
|
||
|
||
- [(1.2)](#class.copy.elision-1.2)
|
||
|
||
in a [*throw-expression*](expr.throw#nt:throw-expression "7.6.18 Throwing an exception [expr.throw]") ([[expr.throw]](expr.throw "7.6.18 Throwing an exception")), when the operand
|
||
is the name of a non-volatile object o with automatic storage duration
|
||
(other than a function parameter or
|
||
a variable introduced by
|
||
the [*exception-declaration*](except.pre#nt:exception-declaration "14.1 Preamble [except.pre]") of a [*handler*](except.pre#nt:handler "14.1 Preamble [except.pre]"))
|
||
that belongs to a scope that does not contain
|
||
the innermost enclosing [*compound-statement*](stmt.block#nt:compound-statement "8.4 Compound statement or block [stmt.block]") associated with a [*try-block*](except.pre#nt:try-block "14.1 Preamble [except.pre]") (if there is one),
|
||
the copy-initialization of the exception object can be omitted by
|
||
constructing o directly into the exception object;
|
||
|
||
- [(1.3)](#class.copy.elision-1.3)
|
||
|
||
in a [coroutine](dcl.fct.def.coroutine "9.6.4 Coroutine definitions [dcl.fct.def.coroutine]"), a copy of a coroutine parameter
|
||
can be omitted and references to that copy replaced with references to the
|
||
corresponding parameter if the meaning of the program will be unchanged except for
|
||
the execution of a constructor and destructor for the parameter copy object;
|
||
|
||
- [(1.4)](#class.copy.elision-1.4)
|
||
|
||
when the [*exception-declaration*](except.pre#nt:exception-declaration "14.1 Preamble [except.pre]") of a[*handler*](except.pre#nt:handler "14.1 Preamble [except.pre]") ([[except.handle]](except.handle "14.4 Handling an exception")) declares an object o,
|
||
the copy-initialization of o can be omitted by treating
|
||
the [*exception-declaration*](except.pre#nt:exception-declaration "14.1 Preamble [except.pre]") as an alias for the exception
|
||
object if the meaning of the program will be unchanged except for the execution
|
||
of constructors and destructors for the object declared by the[*exception-declaration*](except.pre#nt:exception-declaration "14.1 Preamble [except.pre]")[.](#class.copy.elision-1.sentence-5)
|
||
[*Note [2](#class.copy.elision-note-2)*:
|
||
There cannot be a move from the exception object because it is
|
||
always an lvalue[.](#class.copy.elision-1.4.sentence-2)
|
||
â *end note*]
|
||
|
||
Copy elision is not permitted
|
||
where an expression is evaluated in a context
|
||
requiring a constant expression ([[expr.const]](expr.const "7.7 Constant expressions"))
|
||
and in constant initialization ([[basic.start.static]](basic.start.static "6.10.3.2 Static initialization"))[.](#class.copy.elision-1.sentence-6)
|
||
|
||
[*Note [3](#class.copy.elision-note-3)*:
|
||
|
||
It is possible that copy elision is performed
|
||
if the same expression
|
||
is evaluated in another context[.](#class.copy.elision-1.sentence-7)
|
||
|
||
â *end note*]
|
||
|
||
[2](#class.copy.elision-2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6436)
|
||
|
||
[*Example [1](#class.copy.elision-example-1)*: class Thing {public: Thing(); ~Thing();
|
||
Thing(const Thing&);};
|
||
|
||
Thing f() { Thing t; return t;} Thing t2 = f();
|
||
|
||
struct A {void *p; constexpr A(): p(this) {}};
|
||
|
||
constexpr A g() { A loc; return loc;}constexpr A a; // well-formed, a.p points to aconstexpr A b = g(); // error: b.p would be dangling ([[expr.const]](expr.const "7.7 Constant expressions"))void h() { A c = g(); // well-formed, c.p can point to c or be dangling}
|
||
|
||
Here the criteria for elision can eliminate
|
||
the copying of the object t with automatic storage duration
|
||
into the result object for the function call f(),
|
||
which is the non-local object t2[.](#class.copy.elision-2.sentence-1)
|
||
|
||
Effectively, the construction of t can be viewed as directly initializing t2,
|
||
and that object's destruction will occur at program exit[.](#class.copy.elision-2.sentence-2)
|
||
|
||
Adding a move constructor to Thing has the same effect, but it is the
|
||
move construction from the object with automatic storage duration to t2 that is elided[.](#class.copy.elision-2.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[3](#class.copy.elision-3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6481)
|
||
|
||
[*Example [2](#class.copy.elision-example-2)*: class Thing {public: Thing(); ~Thing();
|
||
Thing(Thing&&);private: Thing(const Thing&);};
|
||
|
||
Thing f(bool b) { Thing t; if (b)throw t; // OK, Thing(Thing&&) used (or elided) to throw treturn t; // OK, Thing(Thing&&) used (or elided) to return t} Thing t2 = f(false); // OK, no extra copy/move performed, t2 constructed by call to fstruct Weird { Weird();
|
||
Weird(Weird&);};
|
||
|
||
Weird g(bool b) {static Weird w1;
|
||
Weird w2; if (b)return w1; // OK, uses Weird(Weird&)elsereturn w2; // error: w2 in this context is an xvalue}int& h(bool b, int i) {static int s; if (b)return s; // OKelsereturn i; // error: i is an xvalue}decltype(auto) h2(Thing t) {return t; // OK, t is an xvalue and h2's return type is Thing}decltype(auto) h3(Thing t) {return (t); // OK, (t) is an xvalue and h3's return type is Thing&&} â *end example*]
|
||
|
||
[4](#class.copy.elision-4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L6534)
|
||
|
||
[*Example [3](#class.copy.elision-example-3)*: template<class T> void g(const T&);
|
||
|
||
template<class T> void f() { T x; try { T y; try { g(x); }catch (...) {if (/*...*/)throw x; // does not movethrow y; // moves} g(y); } catch(...) { g(x);
|
||
g(y); // error: y is not in scope}} â *end example*]
|