Перейти к содержимому

Каков размер пустого объекта с

  • автор:

Узнать размер объекта в C++ по его vtable

У тебя в примере вообще нет виртуальных функций. Соответственно, и vtable строится не из чего.

А так ты можешь добавить виртуальную функцию, возвращающую sizeof.

Ivan_qrt ★★★★★
( 27.08.19 15:44:28 MSK )
Ответ на: комментарий от Ivan_qrt 27.08.19 15:44:28 MSK

Я пробовал такое:

class Obj < public: virtual size_t get_size() < return sizeof(decltype(*this)); >>; 

Но при вызвое функции оно возвращает ‘8’

guixoid
( 27.08.19 15:58:57 MSK ) автор топика
Ответ на: комментарий от guixoid 27.08.19 15:58:57 MSK

У классов в C++ минимальный размер sizeof(char). С виртуальными функциями sizeof(void*).

Так же в размере играет роль выравнивание данных.

8 — это указатель на vtable.

Ну и в каждом наследнике должна быть объявлена своя size_t get_size() override . Иначе виртуальная функция будет вызываться для базового класса и возвращать его размер.

Ivan_qrt ★★★★★
( 27.08.19 16:43:09 MSK )
Ответ на: комментарий от Ivan_qrt 27.08.19 15:44:28 MSK

надо еще деструктор виртуальный. этот vtable спавнится в том же объектнике, что и деструктор, а если его нету — жди беды при линковке.

example_cat
( 27.08.19 16:43:44 MSK )
Ответ на: комментарий от Ivan_qrt 27.08.19 16:43:09 MSK

Да, это то что надо, спасибо

guixoid
( 27.08.19 16:47:35 MSK ) автор топика
Ответ на: комментарий от Ivan_qrt 27.08.19 15:44:28 MSK

Пппц, я вначале подумал, что это фрактал начал по c++ шпарить. Нельзя же так.

ox55ff ★★★★★
( 27.08.19 17:52:11 MSK )
Ответ на: комментарий от Ivan_qrt 27.08.19 15:44:28 MSK

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

anonymous
( 27.08.19 21:20:24 MSK )
Ответ на: комментарий от anonymous 27.08.19 21:20:24 MSK

В ЛОР был тред, что у фрактала аватарка пропагандирует гомосексуализм. Ну вот, мужики так поддержали его.

crutch_master ★★★★★
( 28.08.19 04:16:35 MSK )
Последнее исправление: crutch_master 28.08.19 04:17:10 MSK (всего исправлений: 1)

Ответ на: комментарий от crutch_master 28.08.19 04:16:35 MSK

Наскриншотили бы разных на порнхабе.

anonymous
( 28.08.19 04:22:17 MSK )
Ответ на: комментарий от Ivan_qrt 27.08.19 16:43:09 MSK

У классов в C++ минимальный размер sizeof(char). С виртуальными функциями sizeof(void*).

Можешь дать ссылочку на стандарт.

rumgot ★★★★★
( 28.08.19 07:32:16 MSK )
Ответ на: комментарий от guixoid 27.08.19 15:58:57 MSK

class Obj < public: virtual size_t get_size() < return sizeof(decltype(*this)); >>; 

В данном случае слишком сложно, тут decltype не нужен:

class Obj < public: // Как упоминалось, в производных должны // быть свои методы get_size() virtual size_t get_size() < return sizeof(Obj); // или // return sizeof(*this); >// Виртуальный деструктор, куда же без него virtual ~Obj() <> >; 

rumgot ★★★★★
( 28.08.19 09:25:30 MSK )
Ответ на: комментарий от rumgot 28.08.19 07:32:16 MSK

Ну стандарт мне лопатить лень. Вот ссылка на трупастрауса:

Ivan_qrt ★★★★★
( 28.08.19 10:29:10 MSK )
Ответ на: комментарий от rumgot 28.08.19 07:32:16 MSK

А про размер с виртуальными функциями. Это зависит от реализации. Стандартом, вроде как, не описано. Но все делают отдельный vtable и указатель на него в классе.

Ivan_qrt ★★★★★
( 28.08.19 10:49:32 MSK )
Ответ на: комментарий от Ivan_qrt 28.08.19 10:29:10 MSK

Нашел в черновике C++11 стандарта:

1.8 The C ++ object model
5 Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size. An object of trivially copyable or standard-layout type (3.9) shall occupy contiguous bytes of storage.

9 Classes
4 Complete objects and member subobjects of class type shall have nonzero size.107 [ Note: Class objects can be assigned, passed as arguments to functions, and returned by functions (except objects of classes for which copying or moving has been restricted; see 12.8). Other plausible operators, such as equality comparison, can be defined by the user; see 13.5. — end note ]

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

rumgot ★★★★★
( 28.08.19 13:41:49 MSK )
Последнее исправление: rumgot 28.08.19 13:43:41 MSK (всего исправлений: 1)

Размер класса в определенной иерархии

Правило «оптимизации пустых базовых классов» (empty base optimization) позволяет пустым базовым подобъектам иметь размер 0 в составе объекта-наследника. Однако в то же время два различных базовых подобъекта одного и того же типа обязаны иметь разные адреса, даже если они пусты. У вас в вашей иерархии в классе A набирается как минимум 4 различных базовых подобъекта типа F . Это уже требует размера как минимум в 4 минимальных адресуемых единицы памяти.

int main()

то получаем (GCC, Clang)

4 0x7ffcc5ed5f5c 0x7ffcc5ed5f5c 0x7ffcc5ed5f5d 0x7ffcc5ed5f5e 0x7ffcc5ed5f5f 

MSVC++, похоже, полагает, что для последнего (по порядку в памяти) подобъекта F нужен лишь уникальный адрес, но не нужно фактического байта памяти, по каковой причине размер A получается равным 3 . Это нехорошо, ведь какой-то другой — внешний по отношению к A — объект может разместиться по тому же адресу, что и последнее F в A .

struct X < A a; char c; >; int main()
3 000000B30CEFFA44 000000B30CEFFA44 000000B30CEFFA45 000000B30CEFFA46 000000B30CEFFA47 000000B30CEFFA47 

Если я не ошибаюсь, совпадение адресов (F *)(E *)(C *) &a.a и &a.c является нарушением требований спецификации языка, т.е. багом в MSVC++.

С++: Каков размер объекта пустого класса?

Мне было интересно, что может быть размером объекта пустого класса. Это, конечно, не могло быть 0 байтов, так как должно быть возможно ссылаться и указывать на него, как на любой другой объект. Но насколько велик такой объект?

Я использовал эту небольшую программу:

#include using namespace std; class Empty <>; int main()

Результат, полученный мной на компиляторах Visual С++ и Cygwin-g++, был 1 байт! Это было немного удивительно для меня, так как я ожидал, что он будет иметь размер машинного слова (32 бита или 4 байта).

Может ли кто-нибудь объяснить почему размер 1 байт? Почему не 4 байта? Это зависит от компилятора или машины? Кроме того, может ли кто-нибудь дать более убедительную причину, почему пустой объект класса не будет иметь размер 0 байтов?

ОТВЕТЫ

Ответ 1

Цитата Часто задаваемые вопросы по стилю и технике Bjarne Stroustrup С++, причина, по которой размер не равен нулю: «Чтобы гарантировать, что адреса двух разных объектов будут разными». И размер может быть равен 1, потому что выравнивание здесь не имеет значения, поскольку на самом деле ничего не видно.

Ответ 2

В стандарте указано, что все наиболее производные объекты имеют sizeof() >= 1:

Если это бит-поле (class.bit), наиболее производный объект должен иметь ненулевой размер и должен занимать один или несколько байтов хранения. Субъекты базового класса могут иметь нулевой размер. ISO/IEC FDIS 14882: 1998 (E) intro.object

Ответ 3

Это действительно деталь реализации. Когда-то давно я думал, что это может быть нулевой байт или тысяча байт, что он не имеет никакого отношения к спецификации языка. Но, посмотрев на стандарт (раздел 5.3.3), sizeof определяется как всегда возвращающий один или более, независимо от того, что.

Размер самого производного класса должен быть больше нуля.

Это требуется, помимо прочего, для обработки массивов объектов и указателей. Если вашим элементам было присвоено нулевое значение, то &(array[0]) будет идентичным &(array[42]) , что вызовет всевозможные хаосы для ваших циклов обработки.

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

Ответ 4

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

Ответ 5

Существует исключение: массивы длиной 0 строк

#include class CompletlyEmpty < char NO_DATA[0]; >; int main(int argc, const char** argv)
Ответ 6

Я думаю, было бы полезно сослаться на ответ, объясняющий это тоже. boost::compressed_pair Логан Капальдо.

Ответ 7

Размер пустого класса или структуры равен 1

Причина, по которой это происходит, сводится к правильной реализации стандарт, одна из тех, что говорит стандарт С++, заключается в том, что «нет объекта должен иметь тот же адрес в памяти, что и любая другая переменная». Что это самый простой способ обеспечить это? Убедитесь, что все типы имеют ненулевой размер. Для этого компилятор добавляет фиктивный байт к структурам и классам, у которых нет данных и нет виртуальных функции, чтобы они имели размер 1, а не размер 0 и то они гарантированно имеют уникальный адрес памяти.

Ответ 8

Назначение 1 байта для пустого класса зависит от компилятора. Компиляторы должны убедиться, что объекты находятся в разных ячейках памяти, и им необходимо выделить ненулевой размер памяти для объекта. Слушайте заметки по этой теме здесь: http://listenvoice.com/listenVoiceNote.aspx?id=27

Несмотря на то, что компиляторы выделяют ненулевой размер пустого класса, они также выполняют оптимизацию, когда новые классы производятся из пустых классов. Слушайте о простой оптимизации базы данных на опросах по программированию на ListenVoice С++.

Ответ 9

причина для класса без элементов данных, но имеющих размер 1 байт, заключается в том, что этот * сильный текст * должен храниться в памяти, чтобы ссылка или указатель могли указывать на объект этого класса

Ответ 10

пустой класс — этот класс не содержит никакого содержимого.

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

теперь как пустой класс будет представлен в памяти? поскольку он не имеет никакого содержания, чтобы показать свое существование в памяти, но класс присутствует, обязательно показывать его присутствие в памяти. Чтобы показать пустое присутствие класса в памяти, требуется 1 байт.

Ответ 11

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

и то, что вы сказали «Это было немного удивительно для меня, так как я ожидал, что он будет иметь размер машинного слова (32 бита или 4 байта)». будет истинным для ссылочной переменной (слова macine) типа empty(), а не для самого класса (который является абстрактным типом данных),

Ответ 12

Я думаю, что этот вопрос имеет только теоретический интерес, но на практике это не имеет значения.

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

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

Нижняя строка: если вы обнаруживаете, что пишете пустой класс X, просто ставьте все функции-члены. Вам тогда не нужно создавать объекты X, и производные классы никак не будут затронуты.

Ответ 13
#include using namespace std; class Empty < >; int main()

Выход: Хорошо, что у него разные адреса.

Возвращаемый размер 1 гарантирует, что два объекта не будут иметь один и тот же адрес.

Ответ 14

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

Ответ 15

Я думаю, что если размер пустого класса равен нулю, это означает, что он не существует. Чтобы он (класс) существовал, он должен иметь не менее 1 байт, так как этот байт является адресом памяти/ссылки.

Ответ 16

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

Что скрывает class Empty <>

Это заметка о методах, которые C++ создаёт автоматически, даже если вы их не создавали.

Для кого эта заметка? Надеюсь, что она будет интересна начинающим программистам на С++. А опытным программистам позволит лишний раз освежить и систематизировать свои знания.

Итак, если вы написали

class Empty <>;

то, знайте, что на самом деле вы создали примерно вот такой класс:

class Empty < public: // Конструктор без параметров Empty(); // Копирующий конструктор Empty(const Empty &); // Деструктор ~Empty(); // Оператор присвоения Empty& operator=(const Empty &); // Оператор получения адреса Empty * operator&(); // Оператор получения адреса константного объекта const Empty * operator&() const; >;

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

К каким это может привести неприятностям?

Самое неприятное, когда программа работает, но не так как вы хотели. При этом никаких ошибок с точки зрения языка не возникает. Именно к таким неприятностям приводят неявно создаваемые методы.

Пример первый: Конструкторы

Рассмотрим класс, который выдаёт сообщения о создании/удалении объектов и поддерживает статический счётчик объектов (для простоты в виде публичного int).

class CC < public: CC(); ~CC(); static int cnt; >;

int CC::cnt(0); CC::CC() < cnt++; cout CC::~CC()

Что будет делать такая программа?

void f(CC o) <> int main()

Результат может удивить неподготовленного читателя:

create cnt = 1 destroy cnt = 0 destroy cnt = -1 destroy

Складывается ощущение, что объект был создан только один раз, а удалён — трижды. Счётчик объектов уходит в минус. При этом программа спокойно отрабатывает и нигде не валится.

Как вы понимаете, это произошло потому, что мы не учли автоматически созданный конструктор копирования, который только копирует, но ничего не печатает и не корректирует счётчик.

Мы можем исправить эту ситуацию, если сами допишем конструктор копирования

CC::CC(const CC &)

Теперь мы получим абсолютно разумный результат:

create cnt = 1 create (copy) destroy cnt = 1 create (copy) destroy cnt = 1 destroy

Аналогичные засады возникают при присвоении (operator=); но.

Пример второй: Получение адреса

… самые, пожалуй, изысканные подвохи могут возникать, если вы реализовали нетривиальный метод получения адреса

CC * operator&();

но забыли реализовать его двойник, обладающий теми же (или иными?) нетривиальными свойствами:

const CC * operator&() const;

Пока ваша программа ограничивается не-константными объектами:

СС o; CC *p; p = &o;

всё работает. Это может продолжаться очень долго, все уже позабудут, как устроен объект CC, проникнутся к нему доверием и не буду думать на него при появлении ошибок.

Но рано или поздно появится код:

CC const o; CC const *q = &o;
CC * operator&();

Предательски не сработает (про перегрузку по const я уже писал вот тут).

Но хватит, наверно, примеров. Смысл у них у всех примерно один и тот-же. Как же избежать всех описанных неприятностей.

От этих недоразумений очень легко застраховаться!

Самый простой способ — создать прототипы всех методов, создаваемых автоматически и не создавать реализации.

Тогда программа просто не слинкуется и вы получите вполне разумное сообщение. Я получил такое:

/var/tmp//ccGQszLd.o(.text+0x314): In function `main': : undefined reference to `CC::operator&() const'

Ваш компилятор может выразиться чуть-чуть иначе.

Если этот способ кажется вам корявым (у вас есть на то все основания и я с вами солидарен), то можно создать «полноценные» методы, но сделать их приватными.

Тогда вы тоже получите сообщения об ошибках ещё на этапе компиляции.

count2.cpp: In function 'int main()': count2.cpp:22: error: 'const CC* CC::operator&() const' is private count2.cpp:37: error: within this context

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

Ну и третий способ (последний в списке, но не последний по значению) — просто честно реализовать все необходимые методы, не откладывая это дело в долгий ящик 🙂

  • c plus plus
  • программирование

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *