2

Я знаю, что инициализация по умолчанию для не-POD-типов также будет инициализироваться по умолчанию для нестатических не-POD-переменных, вызвав их конструктор по умолчанию. Но я точно не знаю, как это происходит. Вот пример того, что я имею в виду:Смутно, как пустой конструктор, определенный пользователем, инициализирует нестатические переменные-члены, не являющиеся POD.

#include <iostream> 
#include <vector> 
using namespace std; 

class Test2 { 
    public: 
    Test2() {cout <<"Here";} 
}; 

class Test { 
    public: 
    Test() {} 
    Test2 i; 
}; 

int main() { 
    Test foo; 
} 

Выход:

Here 

Основываясь на C++ стандарта на инициализаторах (8,5), для инициализации по умолчанию:

— if T is a non-POD class type (clause 9), the default constructor 
for T is called (and the initialization is ill-formed if T has no 
accessible default constructor); 

Так учитывая это, я ожидаю, что конструктор по умолчанию Test() будет вызван, но мой пустой конструктор по умолчанию для класса Test не инициализирует Test2 i expli citly, но ясно, Test2() получает вызов как-то неявно. Мне интересно, как это происходит?

Аналогично, для инициализации значения (не относящегося к примеру выше), если пустой пользовательский конструктор по умолчанию явно не инициализирует нестационарную переменную-член POD, как эта переменная получает нулевой инициализацию (что я знаю, что она делать)? Поскольку, основываясь на стандарте, кажется, что для инициализации значения все, что происходит, когда у вас есть пользовательский конструктор по умолчанию, заключается в том, что конструктор получает вызов.

Соответствующая часть стандарта C++ для инициализации значений заключается в следующем:

— if T is a class type (clause 9) with a user-declared constructor (12.1), then the 
default constructor for T is called (and the initialization is ill-formed if T has no 
accessible default constructor); 

Этот вопрос похож на c++ empty constructor and member initialization Но разница в том, что вместо того, чтобы спросить, что поведение конечного результата, я бы как знать, почему происходит поведение конечного результата.

+0

компилятора написано следовать правилам, как скомпонованные из стандарта. стандарт говорит X должен произойти в ситуации Y, поэтому компилятор испускает код для выполнения X в ситуации Y. Я не понимаю, как это может сбивать с толку. –

+0

, если вы не инициализируете его в конструкторе, его инициализировали для ou –

+0

@Benjamin: Моя путаница в том, что я вижу, что X должен произойти в ситуации Y с побочными эффектами, где побочные эффекты не объясняются стандартом, который я перечислял выше. – user1082160

ответ

2

В стандарте C++ 11, параграф 12.6 раздела 8:

В не делегировании конструктора, если данный нестатический член данных или базовый класс не обозначен MEM-initializer- идентификатор (включая случай, когда нет никакого мем-инициализатор-лист, так как конструктор не имеет CTOR-инициализатор) и объект не является виртуальным базовым классом абстрактного класса (10.4), а затем

  • если лица представляет собой нестатический элемент данных, который имеет инициализатор скобок или равный-инициализатор, объект инициализируется , как указано в 8,5;
  • в противном случае, если объект является вариантом (9.5), инициализация не выполняется;
  • В противном случае объект инициализируется по умолчанию (8.5).

Вы столкнулись третий случай, когда нет инициализатора для члена и член не является членом вариантом, так что в этом случае по умолчанию инициализируется.

Кроме того, из пункта 10:

В не делегировании конструктор, инициализация происходит в следующем порядке: - Во-первых, и только для конструктора самого производного класса (1.8), виртуальные базовые классы инициализируются в том порядке, в котором они появляются при первом обратном направлении слева направо направленного ациклического графа базовых классов, где «слева направо» представляет собой порядок появления базовых классов в базовом-спецификаторе-списке производного класса.

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

Независимо от того, что указано в конструкторе, члены будут инициализированы непосредственно перед телом конструктора выполняется.

MEM-инициализатор-идентификатор представляет собой идентификатор, используемый для обозначения элемента в списке инициализатора конструктора:

class Test { 
    public: 
    Test() : i() {} // Here `i` is a mem-initializer-id 
    Test2 i; 
}; 
+0

А я вижу, я не знал об этой части стандарта. Просто любопытно, что такое mem-initializer-id? – user1082160

+1

@ user1082160: Я добавил несколько объяснений в свой ответ. –

+0

Последний вопрос, который я заметил из стандартного сообщения u (12.6, пункт 8), на самом деле не упоминает, как для инициализации значения нестатические типы пакетов инициализируются нулем, даже если пользовательский пустой конструктор по умолчанию не инициализирует модуль тип. Из стандарта я бы предположил, что типы pod будут инициализированы по умолчанию, что означает, что он не инициализирован. – user1082160

0

Согласно проекту стандарта С ++ найти на http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf, раздел 12.6.2:

Если заданный нестатический элемент данных или базовый класс не назван идентификатором mem-initializer (включая случай, когда нет списка mem-initializer, поскольку у конструктора нет ctor-initializer), тогда

- Если объект является нестационарным членом данных (возможно, cv-qualified) типа класса (или его массива) или базового класса, а класс сущности - не-POD-класс, объект инициализируется по умолчанию (8.5). Если объект является нестатистическим членом данных типа const-quali-fi, класс сущности должен иметь объявленный пользователем конструктор по умолчанию.

- В противном случае объект не инициализируется. Если объект имеет тип со стандартным качеством или ссылочный тип, или (возможно, cv-qualified) тип класса POD (или его массив), содержащий (прямо или косвенно) член определенного типа, формируется.

Другими словами, если объект типа класса не-POD не отображается в списке инициализации, компилятор интерпретирует это как если бы объект был появился с его конструктор по умолчанию вызывается.

Также обратите внимание, что другие типы (т. Е. Примитивы и типы POD) не инициализируются, что отличается от того, что вы указали в своем вопросе. Глобальные объекты инициализируются нулем, но то же самое не относится к объектам в стеке. Вот небольшая программа, которую я поставил вместе, чтобы проверить это:

#include <iostream> 

class T 
{ 
public: 
    T() {} 

    void put(std::ostream &out) 
    { 
     out << "a = " << a << std::endl; 
     out << "b = " << b << std::endl; 
     out << "c = " << c << std::endl; 
    } 
private: 
    int a; 
    int b; 
    int c; 
}; 

T t2; 

int main() 
{ 
    T t; 
    t.put(std::cout); 
    t2.put(std::cout); 

    return 0; 
} 

Компиляции с г ++ 4.5.2, я получил следующий вывод:

инициализацию
a = 8601256 
b = 3 
c = 2130567168 
a = 0 
b = 0 
c = 0 
+0

Я упомянул инициализацию значения, ноль инициализирует типы pod, а не инициализацию по умолчанию. Здесь u инициализируется по умолчанию T, поэтому типы пакетов не инициализируются. – user1082160

2

Значения типа с определенным пользователем по умолчанию конструктор не выполняет инициализацию нестатических членов POD, если они явно не инициализируются в конструкторе. Например, в this program:

#include <iostream> 

using namespace std; 

struct Foo { 
    // Foo has a user-defined default constructor 
    // that does not initialize i 
    Foo() {} 
    int i; 
}; 

int main() { 
    Foo x{}; // value-initialize x 
    cout << x.i << endl; 
} 

x.i не инициализирован.Программа поэтому технически имеет неопределенное поведение, но в данном случае «неопределенное поведение», скорее всего, означает, что он будет печатать неопределенное целое значение, которое, вероятно, не 0.

Language адвокат аргумент:

  • §12.6. 1p2: «Объект типа класса также может быть инициализирован скопированным-init-list. Используется семантика списка-инициализации, см. 8.5 и 8.5.4."
  • §8.5.4p3: «Инициализация списка объекта или ссылки типа T определяется следующим образом: ... Если в списке инициализаторов нет элементов, а T - это тип класса с конструктором по умолчанию, объект является значением -initialized «.
  • §8.5p7: «Чтобы значение инициализация объект типа T означает: ... если T является (возможно, резюме квалифицированного) типа класса (пункт 9) с предоставленным пользователем конструктора (12.1), то конструктор по умолчанию для T вызывается (и инициализация плохо сформированным, если T не имеет доступный конструктора по умолчанию)
Смежные вопросы