C ++ конструктор по умолчанию - PullRequest
20 голосов
/ 14 мая 2011

С учетом следующего кода:

class temp
{
public:
    string str;
    int num;
};

int main()
{
    temp temp1;
    temp temp2 = temp();

    cout << temp1.str << endl; //Print ""
    cout << temp2.str << endl; //Print ""

    cout << temp1.num << endl; //Print a rand num
    cout << temp2.num << endl; //Print 0
}

Чем они отличаются? & Mdash;

temp temp1;

и

temp temp2 = temp();

Ответы [ 3 ]

23 голосов
/ 14 мая 2011
temp temp1;

Это вызывает конструктор temp по умолчанию для экземпляра с именем temp1.

temp temp2 = temp();

Это вызывает конструктор temp по умолчанию для временного объекта, затем вызывает сгенерированный компилятором конструктор копирования на temp2 с временным объектом в качестве аргумента (это, конечно, предполагает, что компилятор не исключает копии ; это зависит от настроек оптимизации вашего компилятора).

Что касается того, почему вы получаете разные инициализированные значения, уместен раздел 8.5 стандарта:


8.5 Инициализаторы [dcl.init]

Параграф 5:

К Инициализация нуля Объект типа T означает:
  • если T является скалярным типом (3.9), объекту присваивается значение 0 (ноль), преобразованное в T;
  • , если T является типом класса, не являющимся объединением, каждый нестатический элемент данных и каждый подобъект базового класса инициализируются нулями;
  • , если T является типом объединения, первый именованный элемент данных объекта инициализируется нулями;
  • если T является типом массива, каждый элемент инициализируется нулями;
  • , если T является ссылочным типом, инициализация не выполняется.

К инициализация по умолчанию объект типа T означает:

  • , если T является типом класса, отличным от POD (пункт 9), вызывается конструктор по умолчанию для T (и инициализация некорректна, если T не имеет доступного конструктора по умолчанию);
  • если T является типом массива, каждый элемент инициализируется по умолчанию;
  • в противном случае объект инициализируется нулями.

Инициализация значения объекта типа T означает:

  • , если T является типом класса (раздел 9) с объявленным пользователем конструктором (12.1), то вызывается конструктор по умолчанию для T (и инициализация некорректна, если T не имеет доступных конструктор по умолчанию);
  • если T является типом класса без объединения без объявленного пользователем конструктора, то каждый нестатический член данных и компонент базового класса T инициализируется значением;
  • если T является типом массива, то каждый элемент инициализируется значением;
  • в противном случае объект инициализируется нулями.

Пункт 7:

Объект, инициализатором которого является пустой набор скобок, т.е. (), должен быть инициализирован значением.

Пункт 9:

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

12 Специальные функции-члены [special]

Пункт 7:

Неявно объявленный конструктор по умолчанию для класса неявно определяется, когда он используется для создания объекта своего типа (1.8). Неявно определенный конструктор по умолчанию выполняет набор инициализаций класса, которые будут выполняться пользовательским конструктором по умолчанию для этого класса с пустым списком mem-initializer-list (12.6.2) и пустым телом функции.

12.6.2 Инициализация баз и членов [class.base.init]

Пункт 4:

Если данный нестатический элемент данных или базовый класс не назван с помощью mem-initializer-id (включая случай, когда нет mem-initializer-list, потому что конструктор не имеет ctor -инициализатор), затем
  • Если объект является нестатическим членом данных типа (возможно, cv-квалифицированного) класса (или его массива) или базового класса, а класс объекта является классом, отличным от POD, объект инициализируется по умолчанию (8.5). Если сущность является нестатическим членом данных типа с константой, класс сущности должен иметь объявленный пользователем конструктор по умолчанию.
  • В противном случае объект не инициализируется. Если сущность имеет константный тип или ссылочный тип, или (возможно, cv-квалифицированный) тип POD-класса (или его массив), содержащий (прямо или косвенно) член типа const-квалифицированный, программа плохо формируется.

Итак, теперь, когда правила изложены, давайте посмотрим, как они применяются:

temp temp1;

temp - это тип, не относящийся к POD (поскольку он имеет член std::string), и поскольку для temp1 не указан инициализатор, он будет инициализирован по умолчанию (8.5 / 9). Это вызывает конструктор по умолчанию (8.5 / 5). temp имеет неявный конструктор по умолчанию (12/7), который инициализирует по умолчанию элемент std::string, а элемент int вообще не инициализируется (12.6.2 / 4).

temp temp2 = temp();

С другой стороны, временный объект temp инициализируется значением (8.5 / 7), который инициализирует значения всех элементов данных (8.5 / 5), что вызывает конструктор по умолчанию в элементе std::string и ноль - инициализирует элемент int (8.5 / 5).

Конечно, если вам гораздо больше не нужно ссылаться на стандарт в 5+ различных местах, просто убедитесь, что вы явно инициализируете все (например, int i = 0; или используете списки инициализаторов).

5 голосов
/ 14 мая 2011

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

Для компиляторов C ++ 98 оба объявления одинаково влияют на конечные значения объявляемых объектов: элемент str должен статьпусто, в то время как num члены должны содержать непредсказуемое значение.В обоих случаях фактическая инициализация - default-initialization , выполняемая предоставленным компилятором конструктором по умолчанию класса temp.Этот конструктор по умолчанию инициализирует str, но оставляет num неинициализированным.

Для компиляторов C ++ 03 поведение отличается.Для объекта temp1 нет никакой разницы (его num все еще непредсказуемо).Но temp2 инициализация обрабатывается по-другому.В C ++ 03 инициализатор () запускает новый тип инициализации - так называемый value-initialization .Инициализация значения игнорирует предоставленный компилятором конструктор по умолчанию для объекта верхнего уровня и вместо этого работает непосредственно над его подобъектами (в данном случае, с элементами данных).Таким образом, объект temp2 эффективно инициализируется инициализацией значения, которая также устанавливает элемент num в ноль (в дополнение к инициализации str пустой строкой).По этой причине temp2.num заканчивается нулями в компиляторах C ++ 03.

Если в ваших экспериментах вы наблюдали непротиворечивый ноль в temp2.num, это означает, что ваш компилятор следует спецификации C ++ 03 вэто уважение.

4 голосов
/ 14 мая 2011
temp temp1;

Создает инициализированный по умолчанию объект temp. Поскольку вы не указали конструктор по умолчанию для temp, каждый элемент temp также будет инициализирован по умолчанию. Поскольку std::string предоставляет ctor по умолчанию, он инициализируется правильно и имеет четко определенное значение. Однако целое число инициализируется по умолчанию, что определяется реализацией и обычно является случайным значением.

temp temp2 = temp();

Сначала будет создан объект temp, инициализированный значением. Это важно, потому что сам объект является инициализированным значением, равно как и его члены. Для строки это не имеет значения, поскольку инициализация по умолчанию и значение одинаковы, но это имеет значение для целого числа. Значение, инициализированное целым числом, имеет значение 0.
После этого вы просто копируете этих членов в temp2.

Кроме того, этот соответствующий вопрос может быть интересен для вас.
Редактировать : См. Мой комментарий к ответу @In silico для объяснения, почему это не относится к MSVC. : /

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...