Подтвердить что ты не робот

Как выглядит объект в памяти?

Возможный дубликат:
Структура объекта С++ в памяти Vs a Struct
макет памяти объектов С++

Это, наверное, очень глупый вопрос, но я все равно спрошу. Мне любопытно, как выглядит объект в памяти. Очевидно, что в нем должны были быть все его данные-члены. Я предполагаю, что функции для объекта не будут дублироваться в памяти (или, может быть, я ошибаюсь?). Казалось бы, расточительно иметь в памяти 999 объектов с одинаковой функцией, заданной снова и снова. Если в памяти всего 9 функций для всех 999 объектов, то как каждая функция знает, какие данные для членов изменять (я специально хочу знать на низком уровне). Есть ли указатель объекта, который отправляется в функцию за кулисами? Возможно, для каждого компилятора он отличается?

Также, как влияет на это ключевое слово static? Со статическими данными элемента я бы подумал, что все объекты 999 будут использовать то же самое место памяти для своих статических данных элемента. Где это хранится? Статические функции, которые, как я полагаю, также будут иметь одно место в памяти и не должны взаимодействовать с экземплярами объектов, которые, как я думаю, я понимаю.

4b9b3361

Ответ 1

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

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

Функции члена класса существуют только один раз в сегменте кода в памяти. На низком уровне они похожи на обычные глобальные функции, но они получают указатель на this. С Visual Studio на x86 он через ecx регистрируется с помощью thiscall соглашения о вызове.

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

Ответ 2

Вы задали несколько вопросов здесь...

Разметка

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

Статические элементы

Сохраняются отдельно, очевидно. Один экземпляр.

Вызов функций

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

[edit: код самой функции не сохраняется вместе с вашим объектом - это позволяет делать забавные вещи типа delete this и продолжать выполнение функции-члена, если вы больше не получаете доступ к только что удаленному объекту].

Когда у вас есть перегруженные или полиморфные функции, все становится немного более волшебным. Эта статья является объяснением, которое я искал в течение примерно 5 секунд. Я уверен, что их гораздо больше. Я никогда не беспокоился о внутренних вызовах объектов, но всегда приятно знать.

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

Ответ 3

Прежде всего следует отметить, что в С++ термин "объект" включает в себя такие вещи, как целые числа.

Далее, структуры выложены в значительной степени, как вы ожидаете. Один член после следующего в памяти с undefined количеством отступов между.

Когда класс наследуется от другого, класс начнет с его базового класса, который, в свою очередь, может начинаться с собственного базового класса. Таким образом, Derived * и Base * будут иметь одинаковое значение в случаях одиночного наследования. Следуя базовой области (ее членам), в свою очередь, будут производные члены класса, причем между ними будет undefined.

Когда класс наследует более чем одну базу, все становится немного по-другому. Базовые области выкладываются в памяти последовательно. Base1, затем Base2 и т.д., После чего члены производного класса, в свою очередь, выкладываются с суммой undefined между ними.

Если объект имеет класс POD, то гарантируется, что первый член в классе будет находиться в местоположении в памяти, в котором находится объект. Это означает, что Class * и Class- > firstMember * будут одинаковыми. Я не считаю, что это относится к объектам, отличным от POD.

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

Все функции-члены будут иметь свои имена, искаженные, и параметры изменены, чтобы принять this в качестве первого аргумента. Это происходит за кулисами, поскольку компилятор создает материал. Виртуальные функции будут обозначаться vtable. Не виртуальные просто будут решены статически и будут использоваться напрямую.

Статические члены не являются членами объекта, созданного классом. Статический член - это просто глобальная переменная с разной областью.

Ответ 4

Как вы подозреваете, элементы данных (поля) выкладываются последовательно. Это также включает поля базовых классов.

Если класс (или один из его базовых классов) содержит какие-либо виртуальные методы, макет обычно начинается с vptr, то есть указателя на виртуальную таблицу (или vtable), которая представляет собой таблицу указателей на реализацию функций, связанных с этим классом, Обратите внимание, что это не определено стандартом, но AFAIK использует все существующие компиляторы. Кроме того, при множественном наследовании он становится более волосатым, поэтому пусть игнорирует его на данный момент.

+-----------+
|  vptr     |  pointer to vtable which is located elsewhere
+-----------+
|  fieldA   |  first member
|  fieldB   |  ...
|  fieldC   |
|  ...      |
+-----------+

Поля могут занимать больше места, чем сумма их индивидуальных размеров, которая зависит от упаковки (например, упаковка в 1 байт гарантирует отсутствие зазоров, но менее эффективна, чем упаковка 4 или 8 байтов в отношении производительности).

Функции-члены (не статические) получают указатель на объект, обычно через регистр ecx в архитектуре x86. Это также не определено стандартом.

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

Ответ 5

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

Static означает только одну копию.