15 Special member functions [special]

15.7 Construction and destruction [class.cdtor]

Для объекта с нетривиальным конструктором обращение к любому нестатическому члену или базовому классу объекта до начала выполнения конструктора приводит к неопределенному поведению. Для объекта с нетривиальным деструктором обращение к любому нестатическому члену или базовому классу объекта после того, как деструктор завершает выполнение, приводит к неопределенному поведению. [Example:

struct X { int i; };
struct Y : X { Y(); };                  // non-trivial
struct A { int a; };
struct B : public A { int j; Y y; };    // non-trivial

extern B bobj;
B* pb = &bobj;                          // OK
int* p1 = &bobj.a;                      // undefined, refers to base class member
int* p2 = &bobj.y.i;                    // undefined, refers to member's member

A* pa = &bobj;                          // undefined, upcast to a base class type
B bobj;                                 // definition of bobj

extern X xobj;
int* p3 = &xobj.i;                      // OK, X is a trivial class
X xobj;

Другой пример:

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]

Чтобы явно или неявно преобразовать указатель (а glvalue) со ссылкой на объект класса X к указателю (ссылка) для прямого или косвенного базового класса B из X, строительства X и строительства всех своих прямых или косвенных оснований , которые прямо или косвенно derive from B должно начаться, и уничтожение этих классов не должно завершиться, в противном случае преобразование приведет к неопределенному поведению. Чтобы сформировать указатель на (или получить доступ к значению) прямого нестатического члена объекта obj, obj должно быть начато построение и его разрушение не должно завершаться, в противном случае вычисление значения указателя (или доступ к значению члена) приводит к неопределенному поведению. [Example:

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: 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]

Функции-члены, в том числе virtual functions, могут вызываться во время построения или разрушения ([class.base.init]). Когда виртуальная функция вызывается прямо или косвенно из конструктора или из деструктора, в том числе во время создания или уничтожения нестатических элементов данных класса, и объект, к которому применяется вызов, является объектом (вызовите его x) в процессе создания или разрушения, вызываемая функция является последним переопределителем в классе конструктора или деструктора, а не переопределяющим его в более производном классе. Если при вызове виртуальной функции используется явное class member access выражение, а объектное выражение относится к полному объекту x или одному из подобъектов базового класса этого объекта, но не к x одному из его подобъектов базового класса, поведение не определено. [Example:

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]

typeid operator Могут быть использованы в процессе строительства или уничтожения ([class.base.init]). Когда typeid используется в конструкторе (включая mem-initializerили default member initializer для нестатического члена данных) или в деструкторе, или используется в функции, вызываемой (прямо или косвенно) из конструктора или деструктора, если операнд typeid относится к строящемуся объекту или уничтожение, typeid дает std​::​type_­info объект, представляющий класс конструктора или деструктора. Если операнд typeid относится к строящемуся или разрушающемуся объекту, а статический тип операнда не является ни конструктором, ни классом деструктора, ни одной из его баз, поведение не определено.

dynamic_­casts может использоваться во время строительства или разрушения ([class.base.init]). Когда a dynamic_­cast используется в конструкторе (включая mem-initializerинициализатор члена или по умолчанию для нестатического члена данных) или в деструкторе, или используется в функции, вызываемой (прямо или косвенно) из конструктора или деструктора, если операнд элемента dynamic_­cast ссылается для строящегося или разрушаемого объекта этот объект считается наиболее производным объектом, имеющим тип класса конструктора или деструктора. Если операнд dynamic_­cast относится к объекту, находящемуся в процессе создания или уничтожения, а статический тип операнда не является указателем или объектом собственного класса конструктора или деструктора или одной из его баз, это dynamic_­cast приводит к неопределенному поведению. [Example:

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 B
  typeid(*v);           // well-defined: *v has type V, a base of B yields type_­info for B
  typeid(*a);           // undefined behavior: type A not a base of B
  dynamic_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]