C ++: Как узнать размер базового класса SubObject? - PullRequest
3 голосов
/ 02 декабря 2010

.

Здесь Я обсуждал Оптимизацию пустой базы, и MSalters сделал этот интересный комментарий:

Ни один класс не может когда-либоиметь sizeof (класс) == 0, пусто или нет. Но мы говорим конкретно о размере пустого подобъекта базового класса. Ему не нужен ни собственный vtable, ни указатель vtable.Предположим, общая схема указателя vtable со смещением 0;это приведет к тому, что подобъект базового класса нулевого размера будет совместно использовать свой указатель vtable с производным классом.Нет проблем: в любом случае они должны быть идентичными, в этом суть виртуальных функций.

Мой вопрос, в частности, таков: компилятор может оптимизировать, когда мы используем Пустой класс в качестве базового, или нет.Как определить, что он на самом деле делает?

И вообще, как мы можем узнать размер подобъекта базового класса?Является ли размер базового подобъекта одинаковым независимо от того, используем ли мы его в качестве базового или нет?Оптимизируют ли компиляторы только пустые базовые классы?

.

Ответы [ 3 ]

4 голосов
/ 02 декабря 2010

Хорошие ответы.

Кстати, компиляторы MS VC ++ и G ++ могут создавать макеты классов для изучения.

С VC ++ просто запустите cl.exe /c /d1reportAllClassLayout <source>.cpp

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

Чтобы лучше понять, как компиляторы C ++ размещают объекты в памяти, вам могут понравиться http://www.openrce.org/articles/files/jangrayhood.pdf и книга Стэна Липпмана «Внутри объектной модели C ++».

Счастливого взлома!

2 голосов
/ 02 декабря 2010

Минимальный размер объекта равен 1:

class X {};
sizeof(X) >= 1

Но производному классу не нужно выделять место для этого пространства, если оно не используется:

class Y : public X {};
sizeof(Y) >= 1

Такхотя класс X сам по себе занимает 1 байт, он не транслируется в родительский класс.Таким образом, с точки зрения Y класс X занимает 0 байтов.

Итак, здесь мы можем сказать, что компилятор оптимизировал базовый класс (хотя технически он ничего не сделал. Нам просто нужно применить правило, согласно которому нет объектаимеет нулевой размер).

int main()
{
    std::cout << sizeof(X) << ":" << sizeof(Y) << "\n";
}

Создает следующий вывод:

> ./a.exe
1:1
>

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

Резюме:

size_of_type(X) = size_of_type(base) + sum(size_of_type(members)) + padding + (extra stuff like vtable pointer etc);


sizeof(<CLASS>) = min(1, size_of_type(<CLASS>))
0 голосов
/ 02 декабря 2010

Вы не можете.Фактический размер может сильно отличаться от информации sizeof() при использовании в качестве базы.

Еще одним примером, кроме EBO, является виртуальное наследование.

...