Что делает компилятор C ++ для создания объекта? - PullRequest
3 голосов
/ 23 октября 2009

В коде на С так:

{
   int i = 5;
   /* ....... */
}

Компилятор заменит код, переместив указатель стека вниз (для стеков, растущих вниз) на размер типа int, и поместит значение 5 в это место памяти.

Аналогично, в коде C ++, что делает компилятор, если объект создан? Например:

class b
{
   public :
           int p;
           virtual void fun();
};

main()
{
   b   obj;
}

Что будет делать компилятор для приведенного выше кода? Кто-нибудь может объяснить, когда выделяется память, когда выделяется память для виртуальной таблицы и когда вызывается конструктор по умолчанию?

Ответы [ 6 ]

6 голосов
/ 23 октября 2009

На конструкциях

Логически нет никакой разницы между ними:

В обоих случаях стек делается достаточно большим, чтобы вместить объект, и для объекта вызывается конструктор.

Просто обратите внимание:

  • Конструктор для типа POD ничего не делает.
  • Пользовательский тип без конструктора имеет сгенерированный компилятором cosntructor по умолчанию.

Вы можете думать об этом так:

int   x;  // stack frame increased by sizeof(int) default construct (do nothing)
B     a;  // stack frame increased by sizeof(B)   default construct.

В то время как:

int   y(6);  // stack frame increased by sizeof(int) Copy constructor called
B     b(a);  // stack frame increased by sizeof(B)   Copy constructor called

Ok. Конечно, конструктор для типов POD очень тривиален, и компилятор выполнит много оптимизаций (и может практически удалить любой реальный код и даже адрес памяти), но логически вполне нормально думать, что он счастлив таким образом.

Примечание: у всех типов есть конструктор копирования (если вы этого не сделаете, компилятор определяет его) и типы POD, которые вы можете логически рассматривать как конструкцию копирования без каких-либо проблем.

Что касается виртуальных таблиц:

Позвольте мне сначала отметить, что это детали реализации, и не все компиляторы используют их.
Но сам vtable обычно генерируется во время компиляции. Любой объект, которому требуется vtable, имеет невидимый указатель, добавленный к структуре (это включено как часть размера объектов). Затем во время конструирования указатель устанавливается на виртуальную таблицу.

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

Примечание: Вы не можете вызывать виртуальные функции в конструкторе / деструкторе. Поэтому все, что вы можете сказать, это то, что vtable будет правильно инициализирован только после полного завершения конструктора.

3 голосов
/ 23 октября 2009

Семантически то же самое, указатель стека уменьшается (для стеков, растущих вниз) на sizeof b, затем вызывается конструктор по умолчанию для настройки вашего экземпляра.

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

2 голосов
/ 23 октября 2009

Чтобы затронуть вопрос о том, когда выделяется виртуальная таблица. Обычно это делается во время компиляции (хотя это зависит от компилятора).

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

Из-за этого разные экземпляры одного и того же класса будут указывать на одну и ту же виртуальную таблицу.

1 голос
/ 23 октября 2009

На

   b   obj;

Как и в случае с int, указатель стека увеличивается на размер b. Тогда конструктор называется. Конструктор может или не может вызывать новую или любую другую функцию для выделения памяти. Это до реализации б. Сам вызов не инициирует никакого выделения.

vftable является статическим объектом. Он не создан самим объектом. Скорее объект содержит «невидимый» указатель, который указывает на соответствующую ему vftable Его размер указан в размере (б).

0 голосов
/ 24 октября 2009

В соответствии со стандартом Itanium C ++ ABI (который, например, следует GCC), виртуальная таблица сохраняется в отдельной памяти, глобальной для единицы перевода.

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

Таким образом, ответ заключается в том, что виртуальные таблицы выделяются во время компиляции, а во время построения устанавливаются только указатели на них.

0 голосов
/ 23 октября 2009

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

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