Пустое строение и анонимный союз странный случай
Компиляция моего кода как С++ 11 с gcc 4.8.2
и llvm/clang 3.4
на fedora-linux, я получил странные результаты, которые я не мог объяснить...
вот аналогичная программа fedora.
#include <iostream>
using namespace std;
struct A {};
struct C {};
struct B1 : A { union { A a;}; };
struct B2 : A { union { C c;}; };
int main()
{
cout << sizeof(B1) << " " << sizeof(B2) << endl;
}
sizeof(B1) = 2
и sizeof(B2) = 1
Но почему разные размеры? На самом деле у меня есть идея "почему", но я хочу найти точное объяснение или правило С++.
Ответы
Ответ 1
У ребенка B1
есть родительский и под-объект типа A
. Два разных объекта одного и того же типа не могут существовать по одному и тому же адресу, и союз отдельно содержит дополнительный A
родительскому элементу A
.
С B2
пустая оптимизация базы позволяет пустому родительскому элементу A
и C
делиться одним адресом дочернего элемента.
Ответ 2
Я думаю, что будут полезные цитаты из С++ Standard. Первый определяет, что такое подобъект.
2 Объекты могут содержать другие объекты, называемые подобъектами. Субобъект может быть субобъектом-членом (9.2), подобъектом базового класса (п. 10), или элемент массива.
Второй говорит, что два подобъекта одного типа могут не иметь одного и того же адреса
Субобъект базового класса может иметь нулевой размер (раздел 9); однако два подобъекты, которые имеют один и тот же тип класса и принадлежат к одному и тому же большинство производных объектов не должны выделяться по одному и тому же адресу (5.10). -end note]
Итак, в этом определении класса
struct B1 : A { union { A a;}; };
существуют два подобъекта типа A: подобъект базового класса и подобъект элемента a.
Также важно добавить, что каждый член каждого анонимного объединения является членом класса, содержащего анонимные объединения.
Ответ 3
Стандарт С++ 11 можно интерпретировать, чтобы разрешить размер 1 для обоих примеров:
1.8 Объектная модель С++ §6:
Если объектом является бит-поле или подобъект базового класса нулевого размера, адрес этого объекта является адресом первого байта, который он занимает. Два разных объекта, которые не являются ни битовыми полями, ни субобъектами базового класса нулевого размера, должны иметь разные адреса.
Там, по крайней мере, одно ненормативное уведомление, запрещающее его для случая 1, но оно ненормативно:
10 Производные классы §8:
[Примечание. Субобъект базового класса может иметь макет (3.7), отличный от макета самого производного объекта того же типа. Субобъект базового класса может иметь полиморфное поведение (12.7), отличное от полиморфного поведения самого производного объекта того же типа. Субобъект базового класса может иметь нулевой размер (раздел 9); однако два подобъекта, которые имеют один и тот же тип класса и которые принадлежат одному и тому же самому производному объекту, не должны выделяться по одному и тому же адресу (5.10). -end note]
Последний публично доступный проект (n3797 от 2013-10-13), хотя и запрещает первый пример иметь размер 1:
1.8 Объектная модель С++ §6:
Если объектом является бит-поле или подобъект базового класса нулевого размера, адрес этого объекта является адресом первого байта, который он занимает. Два объекта, которые не являются битовыми полями, могут иметь один и тот же адрес, если один является подобъектом другого, или, если хотя бы один является подобъектом базового класса с нулевым размером, и они имеют разные типы; в противном случае они должны иметь разные адреса.
Ответ 4
Благодарю вас, ребята, за быстрый ответ!!! Я немного изменил свой код шаблоном, так что фактические данные объекта одинаковы, но типы шаблонов разные - работает отлично!!! для тех, кто заинтересован, теперь он выглядит примерно так (T не должен равняться нулю):
template<int T> struct A { enum{ val = T < 0 ? -T : T}; };
struct B1 : A<1> { union { A<-1> a;}; };
Благодарю вас