Причуды расположения объектов MSVC - PullRequest
6 голосов
/ 12 февраля 2010

У меня есть простой класс в C ++, который имеет целое число и vtable:

class Something {

   virtual void sampleVirtualMethod();

   int someInteger;
};

Если вы посмотрите на расположение объектов для MSVC (используя / d1reportSingleClassLayout), вы получите:

class Something       size(8):
        +---
 0      | {vfptr}
 4      | someInteger
        +---

Что имеет смысл. 4 байта для указателя vtable и 4 байта для целого числа. Странная вещь, когда я добавляю двойку к классу:

class Something {    
    virtual void sampleVirtualMethod();
    int someInteger;
    **double someDouble;**
};

Я получаю макет этого объекта:

class Something       size(24):
        +---
 0      | {vfptr}
 8      | someInteger
        | <alignment member> (size=4)
16      | someDouble
        +---

Почему разница между смещением 0 и некоторым Integer 8 вместо 4? Vtable как-то вырос до 8 байт? Независимо от того, когда я добавляю двойной, это случается.

Спасибо.

Ответы [ 3 ]

2 голосов
/ 25 февраля 2014

В этом блоге обсуждается та же проблема и приводится пояснение в комментариях Яна Грея, который давно написал компилятор кода компоновки MS C ++.

Перефразируя,vfptr вставляется в макет класса только после того, как другие члены данных были размещены.В зависимости от требований выравнивания элементов данных это означает, что может быть введено ненужное заполнение.Также это происходит только в том случае, если у класса нет базового класса с vfptr.

Отсюда и обходной путь, представленный в сообщении в блоге:

class EmptyBase
{
protected:
    virtual ~EmptyBase() {}
};

class Something : public EmptyBase {    
    virtual void sampleVirtualMethod();
    int someInteger;
    **double someDouble;**
};

sizeof(Something) должно быть 16в этом случае.

1 голос
/ 13 февраля 2010

Я подозреваю, что этот ответ как-то связан с этим. Чтобы процитировать ответ dirkgently , цитируя руководство GCC:

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

В соответствии с этим правилом, после того, как вы добавили 8-байтовый дубль, компилятор должен расположить все по 8-байтовым коэффициентам. Конечно, вы можете переопределить это с помощью #pragma pack (), хотя это будет менее эффективно, если в результате вы получите 8-байтовый член в чем-то отличном от 8-байтовой границы.

0 голосов
/ 12 февраля 2010

Я не могу ответить на ваш вопрос напрямую, потому что нет хорошего оправдания поведению компилятора. Вместо этого я потворствую диким спекуляциям, так как ответа еще не было.

Я подозреваю, что ошибка в алгоритме выравнивания выглядит примерно так:

  • выравнивание структуры (т. Е. Размещение первого элемента) должно быть как минимум такой же ширины, как выравнивание ее самого широкого элемента
  • упс, забыл сосчитать указатель таблицы виртуальных функций в качестве члена

Если эта ошибка существует, я подозреваю, что она осталась с первых дней компиляции как компилятор C с выравниванием по 4 байта. Теперь для компилятора по умолчанию используется значение /Zp8, означающее, что каждая структура выровнена не менее чем на 8 байтов, поэтому в любом случае нет необходимости исправлять выравнивание «первого» элемента.

С уважением, Sherm

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