Files
2025-10-25 03:02:53 +03:00

151 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.3Virtual functions")), can be called
during construction or destruction ([[class.base.init]](class.base.init "11.9.3Initializing 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.1General")),
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.5Class 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.8Type identification")) can be used during construction or destruction ([[class.base.init]](class.base.init "11.9.3Initializing bases and members"))[.](#5.sentence-1)
Whentypeid is used in a constructor (including the[*mem-initializer*](class.base.init#nt:mem-initializer "11.9.3Initializing bases and members[class.base.init]") or default member initializer ([[class.mem]](class.mem "11.4Class 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.7Dynamic cast")) can be used during construction
or destruction ([[class.base.init]](class.base.init "11.9.3Initializing 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.3Initializing 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*]