Код (Text): class A { }; int main() { int x = sizeof(A); // x == 1 A* a = new A; // выделится 1 байт } Почему класс A имеет ненулевой размер? Почему происходит аллокация памяти?
cupuyc Куда иначе будет указывать указатель? На 0? Если да, то все экземпляры будут нулями? Ни разименовать, ни получить ссылку, ахтунг какой-то. А не на 0, это ещё более ахтунг.
мало читали дядю Страуструпа... размер действительно выделяется для того, чтобы два экземпляра этого класса олицетворяли разные вещи... тем более, что объект должен как-то существовать, а обращение к нулевому указателю вызывает исключение... а 1 один байт - потому, что поскольку объект пустой, то выравнивание не имеет никакого значения, тем более, что память выделяется на куче... насколько я помню, это как раз часть стандарта... то, что размер объекта >= 1 байту, если объект не является битовым полем...
Хм.. Я раньше думал, что всякие true_type false_type is_pointer и пр. совершенно никак не сказываются на потреблении ресурсов. Оказывается, под каждый такой тип: Код (Text): template <> struct bool_type<false> { static false_type value; }; выделяется память.
а на самом деле там не один байт =) как минимум еще this в четыре байта и я бы не назвал этот объект пустым. там ведь есть еще несколько дефолтных функций, тихо реализованных компилятором (пусть даже они и реализованы в виде глобальных процедур, с формальной точки зрения это не важно).
this и дефолтные функции в самом объекте не хранятся. Вот если объявить в классе хотя бы один виртуальный метод, то да - размер объекта будет >= 4 байта за счет неявного включения в структуру класса указателя на vtable
проаллоцировать 0 байт невозможно. при компилении без оптимизации генерятся все сущности в том виде как они записаны в проге. при компилении с оптимизацией пустые и неюзанные сущности генериться не будут. (хотя и не помню с какого уровня оптимизированности)
небольшое дополнение к тому, что я сказал выше... вот такая тестовая программа: Код (Text): class AA {}; ... AA* aa1 = new AA(); AA* aa2 = new AA(); printf("%d\n", (char*)(aa2) - (char*)(aa1)); printf("%d %d %d\n", sizeof(AA), sizeof(*aa1), sizeof(*aa2)); delete aa2; delete aa1; ... на выходе имеем (визуал студия): Код (Text): 16 1 1 1 на выходе (мингв): Код (Text): 120 1 1 1 вывод из этого... все компиляторы следуют стандартам, но то, что физически окажется на вашей куче - зависит от реализации классов этим самым компилятором... ЗЫ почему между двумя классами на куче в мингв оказалось 120 байт - сам удивился)
Чего тут удивляться, если ни одна куча не гарантирует выделения блоков памяти по последовательным адресам, тем более продвинутые кучи, заточенные на fast или low fragmentation
Rel, как Вы думаете, можно ли заставить компилятор не выделять память под пустые объекты (ради интереса)? Какой ещё this? где юзается то, если все мемберы статичные? Разве не виртуальные функции влияют на размер объекта?
да-да... я чет не подумал об этом, спасибо... но смысл в другом... адреса разные, значит экземпляры пустых классов разделены... надо попробывать на стеке выделить классы, чуть попозже посмотрю... зачем? если есть какой-то стандарт в языке, то он для чего то нужен... C++ придумали далеко не дураки и Boost кстати тоже... если вам не нравится язык программирования - подберите себе другой... например язык D, я вроде вам уже советовал обратить на него внимание)) тем более, чисто с точки зрения идеалогии, зачем вам пустой объект в полном смысле этого слова? вот например, если вы загляните в одну из реализаций языка Ruby, то увидите, что хоть в языке и есть "пустой объект" ("Nil" или "Null" - не помню уже), но физически он реализован в виде статической переменной языка си с определенным значением... не выделяйте память под пустые объекты сами, или перегрузите malloc (оператор new вроде вызывает malloc, хотя лучше проверить, посмотрев в исходниках) из CRT таким образом, чтобы он не выделял память меньшую 2 байтов, хотя это полный бред))) таблица виртуальных функций вроде идет в памяти перед данными класса... размер увеличивается на (n * sizeof(void*)), где n - количество виртуальных методов...
Rel Наивное заблуждение. В самом объекте хрпнится только один указатель на таблицу виртуальных методов класса, а сама эта таблица представлена в единственном экземпляре в статической памяти, т.к. было бы совершенно глупым расточительством дублировать одну и ту же таблицу в десятках или сотнях объектов одного и того же класса
Rel Имелось ввиду стандартизация конкретного размера, а так да, размер должен быть. cupuyc А вот это кстати не обязательно, компилятор может и убрать переменную.
Booster, мдя.. любопытно: Код (Text): struct true_type {}; struct false_type {}; template <bool b> struct bool_type {}; template <> struct bool_type<false> { static true_type value; }; true_type bool_type<false>::value; template <> struct bool_type<true> { static false_type value; }; false_type bool_type<true>::value; template <typename t> struct is_pointer { static const bool value = false; }; template <typename t> struct is_pointer<t*> { static const bool value = true; }; int func(true_type ptr) { return 2; } int func(false_type ptr) { return 10; } int main() { return func(bool_type<is_pointer<char*>::value>::value) + func(bool_type<is_pointer<int>::value>::value); } получаем: Код (Text): . text:00401000 ; int __cdecl main(int argc, const char **argv, const char *envp) .text:00401000 _main proc near ; CODE XREF: ___tmainCRTStartup+10Ap .text:00401000 mov eax, 0Ch .text:00401005 retn .text:00401005 _main endp
Ещё более любопытно: Код (Text): template <int a, int n> struct pow { static const int value = a * pow<a, n - 1>::value; }; template <int a> struct pow<a, 0> { static const int value = 1; }; int main() { return pow<-1, 1000>::value; } Студия кидает необработанный эксепшн, gcc зацикливается ))