15 Special member functions [special]

15.6 Initialization [class.init]

Когда для объекта типа класса (или его массива) не()указан инициализатор или инициализатор имеет форму , объект инициализируется, как указано в[dcl.init].

Объект типа класса (или его массив) может быть инициализирован явно; видеть[class.expl.init] и[class.base.init].

Когда массив объектов класса инициализируется (явно или неявно) и элементы инициализируются конструктором, конструктор должен вызываться для каждого элемента массива, следуя порядку нижнего индекса; см[dcl.array]. [ Note: Деструкторы для элементов массива вызываются в порядке, обратном их построению. ]end note

15.6.1 Explicit initialization [class.expl.init]

Объект типа класса может быть инициализирован заключенным в круглые скобки expression-list, где expression-list конструируется как список аргументов для конструктора, который вызывается для инициализации объекта. В качестве альтернативы, single assignment-expression может быть указан как initializer using = форма инициализации. Применяется либо семантика прямой инициализации, либо семантика копирования-инициализации; см[dcl.init]. [Example:

struct complex {
  complex();
  complex(double);
  complex(double,double);
};

complex sqrt(complex,complex);

complex a(1);                   // initialize by a call of complex(double)
complex b = a;                  // initialize by a copy of a
complex c = complex(1,2);       // construct complex(1,2) using complex(double,double),
                                // copy/move it into c
complex d = sqrt(b,c);          // call sqrt(complex,complex) and copy/move the result into d
complex e;                      // initialize by a call of complex()
complex f = 3;                  // construct complex(3) using complex(double), copy/move it into f
complex g = { 1, 2 };           // initialize by a call of complex(double, double)

end example] [ не влияет на инициализацию. ]Note: Overloading of the assignment operatorend note

Объект типа класса также может быть инициализирован файлом braced-init-list. Применяется семантика инициализации списка; видеть[dcl.init] и[dcl.init.list]. [Example:

complex v[6] = { 1, complex(1,2), complex(), 2 };

Здесь complex​::​complex(double) вызывается для инициализации v[0] и v[3], complex​::​complex(​double, double) вызывается для инициализации v[1], complex​::​complex() вызывается для инициализации v[2], v[4]и v[5]. Другой пример:

struct X {
  int i;
  float f;
  complex c;
} x = { 99, 88.8, 77.7 };

Здесь x.i инициализируется 99, x.f 88,8 и complex​::​complex(double) вызывается для инициализации x.c. ] [ Фигурные скобки можно опустить в любом агрегате, даже если у агрегата есть члены типа класса с определяемыми пользователем преобразованиями типов; см . ]end exampleNote: initializer-list[dcl.init.aggr]end note

[ Note: Если T это тип класса без конструктора по умолчанию, любое объявление объекта типа T (или его массива) неправильно сформировано, если не initializer указано явно (см.[class.init] И[dcl.init]). ]end note

[ Порядок, в котором инициализируются объекты со статической продолжительностью хранения или хранением потоков, описан в и . ]Note: [basic.start.dynamic] [stmt.dcl]end note

15.6.2 Initializing bases and members [class.base.init]

В определении конструктора для класса инициализаторы для прямых и виртуальных подобъектов базового класса и нестатических членов данных могут быть указаны с помощью a ctor-initializer, который имеет форму

ctor-initializer:
	: mem-initializer-list
mem-initializer-list:
	mem-initializer ...opt
	mem-initializer-list , mem-initializer ...opt
mem-initializer:
	mem-initializer-id ( expression-listopt )
	mem-initializer-id braced-init-list
mem-initializer-id:
	class-or-decltype
	identifier

В mem-initializer-idисходном неквалифицированном поиске identifierвыполняется поиск в области действия класса конструктора, и, если он не найден в этой области, выполняется поиск в области, содержащей определение конструктора. [ Note: Если класс конструктора содержит член с тем же именем, что и прямой или виртуальный базовый класс класса, mem-initializer-id именование члена или базового класса, состоящее из одного идентификатора, относится к члену класса. Для mem-initializer-id скрытого базового класса можно указать полное имя. ] Если не названы класс конструктора, нестатический член данных класса конструктора или прямая или виртуальная база этого класса, объект имеет неправильный формат.end notemem-initializer-idmem-initializer

A mem-initializer-list может инициализировать базовый класс, используя любой, class-or-decltypeкоторый обозначает этот тип базового класса. [Example:

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]

Если a mem-initializer-id неоднозначно, потому что он обозначает как прямой не виртуальный базовый класс, так и унаследованный виртуальный базовый класс, mem-initializer это неправильно сформировано. [Example:

struct A { A(); };
struct B: public virtual A { };
struct C: public A, public B { C(); };
C::C(): A() { }                 // ill-formed: which A?

end example]

A ctor-initializer может инициализировать вариантный член класса конструктора. Если a ctor-initializer указывает более одного mem-initializer для одного и того же члена или для одного и того же базового класса, ctor-initializer это неправильно сформировано.

A mem-initializer-listможет делегировать другому конструктору класса конструктора, используя любой, class-or-decltypeкоторый обозначает сам класс конструктора. Если mem-initializer-idобозначает класс конструктора, он должен быть единственным mem-initializer; конструктор - этоdelegating constructor, а конструктор, выбранный объектом, mem-initializer- этоtarget constructor. Целевой конструктор выбирается по разрешению перегрузки. После возврата целевого конструктора выполняется тело делегирующего конструктора. Если конструктор прямо или косвенно делегирует себе полномочия, программа имеет неправильный формат и диагностика не требуется. [Example:

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]

expression-list Или braced-init-list в mem-initializer используются для инициализации назначенного субобъекта (или, в случае делегирования конструктора, полный класс объекта) в соответствии с правилами инициализаций[dcl.init] для прямой инициализации. [Example:

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: Инициализация, выполняемая каждым из них, mem-initializer представляет собой файлfull-expression. Любое выражение в a mem-initializer оценивается как часть полного выражения, выполняющего инициализацию. ] A, где означает, что виртуальный базовый класс игнорируется во время выполнения конструктора любого класса, который не является самым производным классом.end notemem-initializermem-initializer-id

Временное выражение, привязанное к ссылочному элементу в a, mem-initializer имеет неправильный формат. [Example:

struct A {
  A() : v(42) { }   // error
  const int& v;
};

end example]

В конструкторе без делегирования, если данный потенциально сконструированный подобъект не обозначен a mem-initializer-id (включая случай, когда его нет, mem-initializer-list потому что у конструктора нет ctor-initializer), тогда

  • если объект является нестатическим членом данных, который имеетdefault member initializer либо

    • класс конструктора - этоunion, и никакой другой вариантный член этого союза не обозначен символом mem-initializer-idили

    • класс конструктора не является объединением, и, если предприятие является членом анонимного союза, ни один из членов этого союза не обозначаются mem-initializer-id,

    сущность инициализируется из инициализатора члена по умолчанию, как указано в[dcl.init];

  • в противном случае, если сущность является анонимным объединением или вариантом member ([class.union.anon]), инициализация не выполняется;

  • в противном случае - сущностьdefault-initialized.

[ Note: Anabstract class никогда не является наиболее производным классом, поэтому его конструкторы никогда не инициализируют виртуальные базовые классы, поэтому соответствующий класс mem-initializers может быть опущен. ] Попытка инициализировать более одного нестатического элемента данных объединения приводит к неправильному формату программы. [ После того , как вызов конструктора для класса для объекта с автоматической или динамической продолжительностью хранения завершен, если конструктор не был вызван как часть значения инициализации и член не является ни инициализацией , ни присваивается значение во время выполнения из тело конструктора, член имеет неопределенное значение. ] [end noteNote: XXcompound-statementend noteExample:

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 constructor
  int i;                // OK: i has indeterminate value
  int j = 5;            // OK: j has the value 5
};

end example]

Если данный нестатический член данных имеет как инициализатор члена по умолчанию, так и a mem-initializer, выполняется инициализация, указанная в mem-initializer, и инициализатор члена нестатических данных по умолчанию игнорируется. [ Example: Учитывая

struct A {
  int i = /* some integer expression with side effects */ ;
  A(int arg) : i(arg) { }
  // ...
};

A(int) конструктор просто инициализацииi со значением arg, и побочных эффектов вiинициализаторе члена по умолчанию «S не будет иметь место. ]end example

Временное выражение, привязанное к ссылочному элементу из инициализатора элемента по умолчанию, имеет неправильный формат. [Example:

struct A {
  A() = default;        // OK
  A(int v) : v(v) { }   // OK
  const int& v = 42;    // OK
};
A a1;                   // error: ill-formed binding of temporary to reference
A a2(1);                // OK, unfortunately

end example]

В конструкторе без делегирования деструктором для каждого потенциально сконструированного подобъекта типа класса являетсяpotentially invoked. [ Note: Это положение гарантирует, что деструкторы могут быть вызваны для полностью сконструированных подобъектов в случае возникновения исключения ([except.ctor]). ]end note

В конструкторе без делегирования инициализация выполняется в следующем порядке:

  • Во-первых, и только для конструктораmost derived classвиртуальных базовых классов инициализируются в том порядке, в котором они появляются при обходе направленного ациклического графа базовых классов в глубину слева направо, где «слева направо» порядок появления базовых классов в производном классе base-specifier-list.

  • Затем прямые базовые классы инициализируются в порядке объявления, как они появляются в base-specifier-list (независимо от порядка mem-initializers).

  • Затем нестатические элементы данных инициализируются в том порядке, в котором они были объявлены в определении класса (опять же, независимо от порядка mem-initializers).

  • Наконец, compound-statementвыполняется тело конструктора.

[ Note: Порядок объявления необходим, чтобы гарантировать, что базовые и членские подобъекты уничтожаются в порядке, обратном инициализации. ]end note

[Example:

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]

Имена в expression-list или braced-init-list из a mem-initializer оцениваются в области действия конструктора, для которого mem-initializer указан. [Example:

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) { }
};

инициализируется X​::​r для ссылки X​::​a, инициализируется X​::​b значением параметра конструктора i, инициализируется X​::​i значением параметра конструктора iи инициализируется X​::​j значением X​::​i; это происходит каждый раз, когда создается объект класса X . ] [ Поскольку они оцениваются в области видимости конструктора, указатель может использоваться в элементе a для ссылки на инициализируемый объект. ]end exampleNote: mem-initializerthisexpression-listmem-initializerend note

Дляvirtual member functionsстроящегося объекта можно вызывать функции-члены (в том числе ). Точно так же строящийся объект может быть операндом typeid operator или для dynamic_­cast. Однако, если эти операции выполняются в ctor-initializer (или в функции, вызываемой прямо или косвенно из a ctor-initializer) до завершения всех mem-initializers базовых классов for, программа имеет неопределенное поведение. [Example:

class A {
public:
  A(int);
};

class B : public A {
  int j;
public:
  int f();
  B() : A(f()),     // undefined: 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: calls member function but base C not yet initialized
  i(f()) { }        // well-defined: bases are all initialized
};

end example]

[ Note: [class.cdtor] описывает результат вызовов виртуальных функций typeid и dynamic_­casts во время построения для четко определенных случаев; то есть описывает polymorphic behavior строящийся объект. ]end note

За mem-initializerкоторым следует многоточиеpack expansion , инициализируются базовые классы, указанные в раскрытии пакета в base-specifier-list классе. [Example:

template<class... Mixins>
class X : public Mixins... {
public:
  X(const Mixins&... mixins) : Mixins(mixins)... { }
};

end example]

15.6.3 Initialization by inherited constructor [class.inhctor.init]

Когда конструктор для типаB вызывается для инициализации объекта другого типаD (то есть, когда конструктор былinherited), инициализация продолжается, как если бы конструктор по умолчанию использовался для инициализацииD объекта и каждого подобъекта базового класса, от которого был унаследован конструктор. , за исключением того, чтоB подобъект инициализируется вызовом унаследованного конструктора. Полная инициализация считается одним вызовом функции; в частности, инициализация параметров унаследованного конструктора упорядочивается перед инициализацией любой частиD объекта. [Example:

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 a deleted default constructor
}

struct D2 : B2 {
  using B2::B2;
  B1 b;
};

D2 f(1.0);          // error: B1 has a deleted default constructor

struct 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 X

template<class T> struct Log : T {
  using T::T;       // inherits all constructors from class T
  ~Log() { std::clog << "Destroying wrapper" << std::endl; }
};

Шаблон классаLog обертывает любой класс и пересылает все его конструкторы, одновременно записывая сообщение в стандартный журнал всякий раз, когда объект классаLog уничтожается. ]end example

Если конструктор был унаследован от нескольких подобъектов базового класса типаB, программа имеет неправильный формат. [Example:

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);       // ill-formed: 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 constructor

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

Когда объект инициализируется унаследованным конструктором, инициализация объекта завершается, когда завершается инициализация всех подобъектов.