дефолтные различия ctor между gcc 4.6 и 4.7

в GCC 4.6.1, когда я объявляю экземпляр моего собственного типа, который имеет конструктор по умолчанию, и если я создаю экземпляр объекта этого типа и инициализирую его фигурными скобками ( например, Foo my_foo {};), члены POD в этом классе будут только инициализировать ноль, если нет другого объявленного конструктора. Если нет другого конструктора, кроме дефолтного, они будут нулевыми, как ожидалось.

но в GCC 4.7.3 нулевая инициализация происходит в любом случае, что является поведением I ожидаемый.

в чем здесь разница? Это ошибка компилятора? Обе эти версии GCC поддерживают конструкторы по умолчанию стандарта C++11.

нет никакой реальной необходимости придерживаться старой версии GCC, но я хотел бы понять, что здесь происходит.

примечание: Я по умолчанию основной ctor, op=. и скопируйте ctor просто, чтобы сохранить тип, используемый с вариадическими функциями (clang требует этого, чтобы классифицировать класс как POD, хотя gcc позволяет мне уйти с использованием тип с variadic функциями даже с определяемым пользователем главным ctor. бонусные баллы, если вы можете сказать мне, почему.)

вот пример программы для иллюстрации, включая некоторые выходные данные внизу (из двоичных файлов, скомпилированных с обеими версиями GCC):

#include <cstdio>

// pod and pod_wctor are identical except that pod_wctor defines another ctor

struct pod {
    pod( void ) = default;
    pod( const pod& other ) = default;
    pod& operator=( const pod& other ) = default;

    int x,y,z;
};

struct pod_wctor {
    pod_wctor( void ) = default;
    pod_wctor( const int setx, const int sety, const int setz ) : x(setx), y(sety), z(setz) { }
    pod_wctor( const pod_wctor& other ) = default;
    pod_wctor& operator=( const pod_wctor& other ) = default;

    int x,y,z;
};

int main ( void ) {

    printf("the following shuold be uninitialized:n");

    pod pee;
    printf( "    %i,%i,%in", pee.x, pee.y, pee.z);

    pod_wctor podtor;
    printf( "    %i,%i,%in", podtor.x, podtor.y, podtor.z);

    printf("the following shuold be initialized to 0,0,0:n");

    pod peenit{};
    printf( "    %i,%i,%in", peenit.x, peenit.y, peenit.z );

    pod_wctor podtornit{};
    printf( "    %i,%i,%in", podtornit.x, podtornit.y, podtornit.z );

    return 0;

}

// compiled with: g++ m.cpp -std=gnu++0x
// g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 (i386)
/****************** output *******************
the following shuold be uninitialized:
    10381592,134513249,134520820
    134513969,134513504,0
the following shuold be initialized to 0,0,0:
    0,0,0
    7367877,134513945,8724468
*********************************************/

// compiled with: g++ m.cpp -std=gnu++0x
// gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu4) (i386)
/****************** output *******************
the following shuold be uninitialized:
    -1218358300,-1217268232,134520832
    134514450,1,-1079827548
the following shuold be initialized to 0,0,0:
    0,0,0
    0,0,0
*********************************************/

1 ответов


путем добавления конструктор pod_wctor( const int setx, const int sety, const int setz ) : x(setx), y(sety), z(setz) { } для вашего класса он теряет статус агрегата: [dcl.в этом.aggregate] / 1

агрегат-это массив или класс (пункт 9) без пользовательских конструкторов

это все еще стручок, потому что тривиальный класс только не нужно иметь нетривиальных по умолчанию ctors: [класс] / 6

A тривиальный класс - это класс, который имеет значение по умолчанию конструктор (12.1), не имеет нетривиальных конструкторов по умолчанию, и тривиально копируется.


интересным моментом здесь является то, что для агрегата инициализация списка pod peenit{}; выполняет агрегатную инициализацию:

List-инициализация объекта или ссылки типа T определяется следующим образом:

  • если T является агрегатом, выполняется агрегатная инициализация (8.5.1). [...]
  • в противном случае, если в списке инициализаторов нет элементов и T - тип класса с конструктором по умолчанию, объект инициализируется значением.

(Примечание: это пересмотренный порядок. AFAIK, в самом Стандарте порядок этих двух точек обращен, что должно быть дефектом,поскольку каждая совокупность имеет ctor по умолчанию - неявно объявленный и определенный.)

Aggregate-инициализация приводит к инициализации значения int члены: [РСН.в этом.aggr] / 7

если их меньше инициализатор-п. в списке, чем есть члены в совокупности, тогда каждый член, явно не инициализированный, должен быть инициализирован из пустого списка инициализаторов

и [dcl.в этом.list] / 3 "в противном случае, если в списке инициализаторов нет элементов, объект инициализируется значением"


однако, для non-aggregate pod_wctor список-инициализация pod_wctor podtornit{} непосредственно выполняет инициализацию значения, которая вызывает ctor по умолчанию. [класс.ctor] / 6 указывает:

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

и в [классе.основа.init] / 8, находим:

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

  • [...]
  • в противном случае сущность инициализируется по умолчанию (8.5).

ctor по умолчанию не гарантирует обнуление членов, потому что это только инициализация членов по умолчанию.


разница между инициализацией по умолчанию и значением: [dcl.init]

[7] к по умолчанию-инициализировать объект типа T означает:

  • если T это (возможно cv-квалифицированный) тип класса, по умолчанию конструктор для T называется [...]
  • [...]
  • в противном случае инициализация не выполняется.

[...]

[8] к значение-инициализировать объект типа T означает:

  • если T это (возможно cv-qualified) тип класса без конструктора по умолчанию или конструктора по умолчанию, который предоставляется пользователем или удаляется, то объект default-инициализировано;
  • если T это (возможно cv-qualified) тип класса non-union без предоставленного пользователем или удаленного конструктора по умолчанию, тогда объект инициализируется нулем и, если T имеет нетривиальный конструктор по умолчанию, инициализированный по умолчанию;
  • [...]
  • в противном случае объект инициализируется нулем.

(я признаю, что это смутило меня, и мне пришлось пересмотреть мой ответ.)

pod_wctor имеет конструктор по умолчанию, который является не пользователем. Поэтому для списка-инициализация pod_wctor podtornit{} вторая пуля значением-инициализации применяется. Объект и ноль-инициализировать, что приводит к нулевой инициализации ее членов. Только затем будет ли он инициализирован по умолчанию, и будет вызван ctor по умолчанию. Последний ничего не делает, но первый гарантирует участники будут обнулены.