151 lines
8.1 KiB
Markdown
151 lines
8.1 KiB
Markdown
[class.cdtor]
|
||
|
||
# 11 Classes [[class]](./#class)
|
||
|
||
## 11.9 Initialization [[class.init]](class.init#class.cdtor)
|
||
|
||
### 11.9.5 Construction and destruction [class.cdtor]
|
||
|
||
[1](#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[.](#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[.](#1.sentence-2)
|
||
|
||
[*Example [1](#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](#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[.](#2.sentence-1)
|
||
|
||
[*Example [2](#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](#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[.](#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[.](#3.sentence-2)
|
||
|
||
[*Example [3](#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](#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"))[.](#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[.](#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[.](#4.sentence-3)
|
||
|
||
[*Example [4](#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](#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"))[.](#5.sentence-1)
|
||
|
||
Whentypeid is used in a constructor (including the[*mem-initializer*](class.base.init#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[.](#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[.](#5.sentence-3)
|
||
|
||
[6](#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"))[.](#6.sentence-1)
|
||
|
||
When adynamic_cast is used in a constructor (including the[*mem-initializer*](class.base.init#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[.](#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[.](#6.sentence-3)
|
||
|
||
[*Example [5](#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*]
|