Инициализация объединения с нетривиальным конструктором

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

Теперь я хочу использовать эту структуру в объединении, но получаю ошибки, потому что у нее нетривиальный конструктор.

Итак, вопрос 1. Предоставляет ли встроенный конструктор конструктора по умолчанию гарантировать, что все члены структуры будут инициализированы нулями? Нетривиальный конструктор просто выполняет набор всех членов в «0», чтобы обеспечить чистую структуру.

Вопрос 2: Если конструктор должен быть указан в базовой структуре, как можно реализовать объединение, чтобы содержать этот элемент и обеспечить инициализированный базовый элемент 0?

    Вопрос 1: Конструкторы по умолчанию инициализируют элементы POD до 0 согласно стандарту C ++. См. Цитируемый текст ниже.

    Вопрос 2: Если конструктор должен быть указан в базовом classе, то этот class не может быть частью объединения.

    Наконец, вы можете предоставить конструктор для вашего объединения:

    union U { A a; B b; U() { memset( this, 0, sizeof( U ) ); } }; 

    Для Q1:

    Из C ++ 03, 12.1 Конструкторы, стр. 190

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

    Из C ++ 03, 8.5 Инициализаторы, стр. 145

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

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

    Для нулевой инициализации объекта типа T означает:

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

    Для Q2:

    Из C ++ 03, 12.1 Конструкторы, стр. 190

    Конструктор тривиален, если он неявно объявлен по умолчанию и если:

    • его class не имеет виртуальных функций (10.3) и нет виртуальных базовых classов (10.1) и
    • все прямые базовые classы его classа имеют тривиальные конструкторы и
    • для всех нестатических членов данных своего classа, которые относятся к типу classа (или его массиву), каждый такой class имеет тривиальный конструктор

    Из C ++ 03, 9.5 Союзов, стр. 162

    Объединение может иметь функции-члены (включая конструкторы и деструкторы), но не виртуальные (10.3) функции. Союз не должен иметь базовые classы. Объединение не должно использоваться как базовый class. Объектом classа с нетривиальным конструктором (12.1) является нетривиальный конструктор копии (12.8), нетривиальный деструктор (12.4) или нетривиальный оператор присваивания копии (13.5.3, 12.8) не может быть членом объединения, и массив таких объектов

    Все изменилось к лучшему на C ++ 11.

    Теперь вы можете законно сделать это, как описано самим Страуступом (я дошел до этой ссылки из статьи Википедии на C ++ 11 ).

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

     #include  // Required for placement 'new'. struct Point { Point() {} Point(int x, int y): x_(x), y_(y) {} int x_, y_; }; union U { int z; double w; Point p; // Illegal in C++03; legal in C++11. U() {new(&p) Point();} // Due to the Point member, a constructor // definition is now *required*. }; 

    Строуструп идет немного подробнее.

    Члены профсоюза AFAIK могут не иметь конструкторов или деструкторов.

    Вопрос 1: нет, такой гарантии нет. Любой член POD не в списке инициализации конструктора получает инициализацию по умолчанию, но это с конструктором, который вы определяете, и имеет список инициализаторов. Если вы не определяете конструктор или вы определяете конструктор без списка инициализаторов и пустого тела, члены POD не будут инициализированы.

    Члены Non-POD всегда будут построены через свой конструктор по умолчанию, который, если он будет синтезирован, снова не будет инициализировать члены POD. Учитывая, что члены профсоюза могут не иметь конструкторов, вам в значительной степени гарантируется, что POD-члены структур в объединении не будут инициализированы.

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

     struct foo { int a; int b; }; union bar { int a; foo f; }; bar b = { 0 }; 

    Как упоминалось в комментарии Грега Роджерса к сообщению незваного , вы можете дать своему союзу конструктор (и деструктор, если хотите):

     struct foo { int a; int b; }; union bar { bar() { memset(this, 0, sizeof(*this)); } int a; foo f; }; 

    Можете ли вы сделать что-то подобное?

     class Outer { public: Outer() { memset(&inner_, 0, sizeof(inner_)); } private: union Inner { int qty_; double price_; } inner_; }; 

    … или что-то вроде этого?

     union MyUnion { int qty_; double price_; }; void someFunction() { MyUnion u = {0}; } 

    Вам придется подождать, пока C ++ 0x будет поддерживаться компиляторами, чтобы получить это. До тех пор, извините.

    Давайте будем гением компьютера.