Задача про размер класса
От: Sir-G  
Дата: 11.05.11 08:02
Оценка: 2 (2) -1
Условие задачи. Даны классы:

class Base { 
    int a; 
    char b; 
}; 

class Derived : public Base { 
    char c; 
    int d; 
};


Предположим, что sizeof( int ) == 4 и компилятор выравнивает int-поля на 4. Таким образом, sizeof( Base ) == 8.

Внимание, вопрос! Какой при этом размер класса Derived? Возможно, кого-то ответ удивит. Может быть 12 или 16.

При компиляции в gcc получается 12, попробуйте объяснить как это возможно. При компиляции в MSVC 2008 получается 16. Связанный вопрос: почему MS не экономят, как gcc? Может быть какие-то бонусы от этого? (есть одно предположение) Или просто лень реализовывать было?

Еще более интересный вопрос, и на него я не знаю ответа (может кто знает?). Если сделать оба поля Base публичными (одного недостаточно!), то размер становится 16! При этом публичность членов Derived на размер не влияет.
Re: Задача про размер класса
От: Uzumaki Naruto Ниоткуда  
Дата: 11.05.11 08:06
Оценка:
см. выравнивание

Re: Задача про размер класса
От: Bell Россия  
Дата: 11.05.11 08:35
Оценка: 7 (2)
Здравствуйте, Sir-G, Вы писали:

SG>Условие задачи. Даны классы:


SG>
SG>class Base { 
SG>    int a; 
SG>    char b; 
SG>}; 

SG>class Derived : public Base { 
SG>    char c; 
SG>    int d; 
SG>};
SG>


SG>Предположим, что sizeof( int ) == 4 и компилятор выравнивает int-поля на 4. Таким образом, sizeof( Base ) == 8.


SG>Внимание, вопрос! Какой при этом размер класса Derived? Возможно, кого-то ответ удивит. Может быть 12 или 16.

Это зависит от реализации. Вот выдержка из драфта:

10/8
[ Note: A base class subobject might have a layout (3.7) different from the layout of a most derived object
of the same type.
...


SG>При компиляции в gcc получается 12, попробуйте объяснить как это возможно.

Видимо gcc упаковывает Base::b и Derived::c "рядом", добавляя 2 байта паддинга перед Derived::d.

SG>При компиляции в MSVC 2008 получается 16. Связанный вопрос: почему MS не экономят, как gcc? Может быть какие-то бонусы от этого? (есть одно предположение) Или просто лень реализовывать было?

Скорее второе.

SG>Еще более интересный вопрос, и на него я не знаю ответа (может кто знает?). Если сделать оба поля Base публичными (одного недостаточно!), то размер становится 16! При этом публичность членов Derived на размер не влияет.

Можно предположить, что это попытка сделать объекты/подобъекты Base более устойчивыми к низкоуровневым операциям типа memcpy — ведь в случае public членов Base становится POD-типом, а это может спровоцировать применение таких низкоуровневых операций.
Любите книгу — источник знаний (с) М.Горький
Re: смотри опции компилятора
От: B0FEE664  
Дата: 11.05.11 09:00
Оценка:
Здравствуйте, Sir-G, Вы писали:

SG>При компиляции в gcc получается 12, попробуйте объяснить как это возможно. При компиляции в MSVC 2008 получается 16. Связанный вопрос: почему MS не экономят, как gcc?

MS перекладывает это на плечи программиста. В студии 'свойства проекта'->'C/C++'->'генерация кода'->'выравнивание членов структуры'-> 1 или 2 или 4 или 8 или 16
или '/Zpномер' опция компиляции.
И каждый день — без права на ошибку...
Re[2]: смотри опции компилятора
От: dilmah США  
Дата: 11.05.11 09:03
Оценка: +1
BFE>MS перекладывает это на плечи программиста. В студии 'свойства проекта'->'C/C++'->'генерация кода'->'выравнивание членов структуры'-> 1 или 2 или 4 или 8 или 16
BFE>или '/Zpномер' опция компиляции.

Речь не о отключении выравнивания.
речь об оптимизации -- гсс использует паддинг в конце базового класса для накладывания туда производного.
Re[2]: Задача про размер класса
От: Erop Россия  
Дата: 11.05.11 09:10
Оценка:
Здравствуйте, Bell, Вы писали:

SG>>Еще более интересный вопрос, и на него я не знаю ответа (может кто знает?). Если сделать оба поля Base публичными (одного недостаточно!), то размер становится 16! При этом публичность членов Derived на размер не влияет.

B>Можно предположить, что это попытка сделать объекты/подобъекты Base более устойчивыми к низкоуровневым операциям типа memcpy — ведь в случае public членов Base становится POD-типом, а это может спровоцировать применение таких низкоуровневых операций.

IMHO, дело тут не в том, что что-то может кого-то спровоцировать, а то, что POD можно пересылать бинарно. Так что нельзя делать разный лэйаут объекта в подобъекте и в MDT...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Задача про размер класса
От: Sir-G  
Дата: 11.05.11 09:34
Оценка:
Здравствуйте, Bell, Вы писали:

B>Видимо gcc упаковывает Base::b и Derived::c "рядом", добавляя 2 байта паддинга перед Derived::d.

Да, Derived::c вставляется в паддинг предка, насколько я помню как вы написали.

SG>>При компиляции в MSVC 2008 получается 16. Связанный вопрос: почему MS не экономят, как gcc? Может быть какие-то бонусы от этого? (есть одно предположение) Или просто лень реализовывать было?

B>Скорее второе.
Возможно, это было сделано для низкоуровневых операций, например, можно не боясь делать memset на весь размер класса Base. Но может просто так было проще реализовать.

SG>>Еще более интересный вопрос, и на него я не знаю ответа (может кто знает?). Если сделать оба поля Base публичными (одного недостаточно!), то размер становится 16! При этом публичность членов Derived на размер не влияет.

B>Можно предположить, что это попытка сделать объекты/подобъекты Base более устойчивыми к низкоуровневым операциям типа memcpy — ведь в случае public членов Base становится POD-типом, а это может спровоцировать применение таких низкоуровневых операций.
Ооо, точно!!! Я думаю в этом и была задумка. Спасибо за ответ!
Re[3]: смотри опции компилятора
От: Sir-G  
Дата: 11.05.11 09:36
Оценка:
Здравствуйте, dilmah, Вы писали:


D>речь об оптимизации -- гсс использует паддинг в конце базового класса для накладывания туда производного.

Да, вопрос был в этом. По моему опыту некоторых программистов это удивляет.
Re[3]: Задача про размер класса
От: Sir-G  
Дата: 12.05.11 12:14
Оценка:
Здравствуйте, Erop, Вы писали:

E>IMHO, дело тут не в том, что что-то может кого-то спровоцировать, а то, что POD можно пересылать бинарно. Так что нельзя делать разный лэйаут объекта в подобъекте и в MDT...


Я тут посмотрел стандарт, и там указан специальный случай наследования от POD-типов (см. упоминания про base-class subobject). Так что <вроде бы> gcc имеет право делать так же, как в случае приватных полей. Но наверно может кого-то спровоцировать всё же.

3.9 

2 For any object (other than a base-class subobject) of POD type T, whether or not the object holds a valid
value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or
unsigned char.36) If the content of the array of char or unsigned char is copied back into the
object, the object shall subsequently hold its original value. 

3 For any POD type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1
nor obj2 is a base-class subobject, if the value of obj1 is copied into obj2, using the memcpy library
function, obj2 shall subsequently hold the same value as obj1.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.