Должен ли пустой базовый класс влиять на макет производного класса? - PullRequest
5 голосов
/ 14 октября 2011

Стандарт C ++ (цитата из черновика n3242) гласит следующее о подобъектах [intro.object]:

Если объект не является битовым полем или подобъектом базового класса с нулем размер, адрес этого объекта является адресом первого байта его занимает. Два разных объекта, которые не являются ни битовыми полями, ни базовыми Подобъекты класса нулевого размера должны иметь разные адреса.

Теперь, учитывая следующий фрагмент:

struct empty { };
struct member: empty { };
struct derived: empty { member m; };

int main(void)
{
    printf("%d", sizeof(derived));
    return 0;
}

gcc, я полагаю, печатает 2, а Visual C ++ 2010 печатает 1. Я подозреваю, что gcc использует стандарт, чтобы означать, что вы не можете использовать псевдоним для хранения типов, если они представляют разные объекты. Бьюсь об заклад, MSVC использует стандарт, чтобы означать, что если один подобъект имеет нулевой размер, вы можете делать все, что захотите.

Это неуточненное поведение?

Ответы [ 4 ]

5 голосов
/ 14 октября 2011

Расширение моего предыдущего комментария:

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

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

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

Итак, если члены имеют разные типы (пустые и char), они могут иметь один и тот же адрес. Если они относятся к одному и тому же типу, они не могут этого сделать, потому что это нарушит тесты на идентичность объекта, такие как if (this != &that), иногда используемые для проверки таких вещей, как самоопределение.

Кстати, Microsoft согласна, что это ошибка в их компиляторе, но есть другие, более срочные, проблемы, которые нужно исправить в первую очередь.

4 голосов
/ 14 октября 2011

Это зависит от реализации.

Стандарт явно разрешает Оптимизацию пустой базы, но не требует ее.На самом деле, стандарт не требует ничего о макете классов в памяти, только то, что определенные классы будут совместимы друг с другом (но не с тем, что такое общий макет).Порядок членов также указывается (когда нет промежуточного спецификатора доступности), но допускается заполнение, верхние и нижние колонтитулы, а также всякие странные вещи.

3 голосов
/ 14 октября 2011

В окончательной версии стандарта C ++ 11 этот абзац был изменен следующим образом:

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

Хотя я не уверен, что понимаю, как это связано с размерами объектов.

1 голос
/ 14 октября 2011

В этой теме есть хорошие объяснения.Я просто хотел добавить, что, чтобы обойти эту проблему раздувания структуры, вы можете просто сделать empty класс шаблоном, так что создание экземпляра с другим аргументом шаблона делает его другим классом:

template<class T>
struct empty { };
struct member: empty<member> { };
struct derived: empty<derived> { member m; };

int main(void)
{
    printf("%d\n", sizeof(derived));
    return 0;
}

Outputs 1.

Это причина, по которой следует избегать использования boost::noncopyable в больших проектах.

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