Почему выделяется память?

Тема в разделе "LANGS.C", создана пользователем cupuyc, 11 янв 2011.

  1. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    Код (Text):
    1. class A
    2. {
    3. };
    4.  
    5. int main()
    6. {
    7.   int x = sizeof(A); // x == 1
    8.   A* a = new A; // выделится 1 байт
    9. }
    Почему класс A имеет ненулевой размер? Почему происходит аллокация памяти?
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    А почему не должна? Объект же должен иметь хоть какой-нибудь размер или нет?
     
  3. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    Зачем?
     
  4. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    cupuyc
    Куда иначе будет указывать указатель? На 0? Если да, то все экземпляры будут нулями? Ни разименовать, ни получить ссылку, ахтунг какой-то. А не на 0, это ещё более ахтунг.
     
  5. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    А вообще размер классов не стандартизирован, так что это лишь частный случай.
     
  6. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    мало читали дядю Страуструпа... размер действительно выделяется для того, чтобы два экземпляра этого класса олицетворяли разные вещи... тем более, что объект должен как-то существовать, а обращение к нулевому указателю вызывает исключение... а 1 один байт - потому, что поскольку объект пустой, то выравнивание не имеет никакого значения, тем более, что память выделяется на куче...

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

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    Хм.. Я раньше думал, что всякие true_type false_type is_pointer и пр. совершенно никак не сказываются на потреблении ресурсов. Оказывается, под каждый такой тип:
    Код (Text):
    1. template <>
    2. struct bool_type<false>
    3. {
    4.   static false_type value;
    5. };
    выделяется память.
     
  8. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    а экземпляры этих типов не создаются, как правило
     
  9. NeuronViking

    NeuronViking New Member

    Публикаций:
    0
    Регистрация:
    29 окт 2004
    Сообщения:
    476
    Адрес:
    где-то в Сиднее
    а на самом деле там не один байт =) как минимум еще this в четыре байта
    и я бы не назвал этот объект пустым. там ведь есть еще несколько дефолтных функций, тихо реализованных компилятором (пусть даже они и реализованы в виде глобальных процедур, с формальной точки зрения это не важно).
     
  10. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    this и дефолтные функции в самом объекте не хранятся. Вот если объявить в классе хотя бы один виртуальный метод, то да - размер объекта будет >= 4 байта за счет неявного включения в структуру класса указателя на vtable
     
  11. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    проаллоцировать 0 байт невозможно.
    при компилении без оптимизации генерятся все сущности в том виде как они записаны в проге.
    при компилении с оптимизацией пустые и неюзанные сущности генериться не будут. (хотя и не помню с какого уровня оптимизированности)
     
  12. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    небольшое дополнение к тому, что я сказал выше... вот такая тестовая программа:
    Код (Text):
    1. class AA {};
    2. ...
    3. AA* aa1 = new AA();
    4. AA* aa2 = new AA();
    5. printf("%d\n", (char*)(aa2) - (char*)(aa1));
    6. printf("%d %d %d\n", sizeof(AA), sizeof(*aa1), sizeof(*aa2));
    7. delete aa2;
    8. delete aa1;
    9. ...
    на выходе имеем (визуал студия):
    Код (Text):
    1. 16
    2. 1 1 1
    на выходе (мингв):
    Код (Text):
    1. 120
    2. 1 1 1
    вывод из этого... все компиляторы следуют стандартам, но то, что физически окажется на вашей куче - зависит от реализации классов этим самым компилятором...

    ЗЫ почему между двумя классами на куче в мингв оказалось 120 байт - сам удивился)
     
  13. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Чего тут удивляться, если ни одна куча не гарантирует выделения блоков памяти по последовательным адресам, тем более продвинутые кучи, заточенные на fast или low fragmentation
     
  14. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    Rel, как Вы думаете, можно ли заставить компилятор не выделять память под пустые объекты (ради интереса)?

    Какой ещё this? где юзается то, если все мемберы статичные?

    Разве не виртуальные функции влияют на размер объекта?
     
  15. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    да-да... я чет не подумал об этом, спасибо... но смысл в другом... адреса разные, значит экземпляры пустых классов разделены... надо попробывать на стеке выделить классы, чуть попозже посмотрю...

    зачем? если есть какой-то стандарт в языке, то он для чего то нужен... C++ придумали далеко не дураки и Boost кстати тоже... если вам не нравится язык программирования - подберите себе другой... например язык D, я вроде вам уже советовал обратить на него внимание)) тем более, чисто с точки зрения идеалогии, зачем вам пустой объект в полном смысле этого слова? вот например, если вы загляните в одну из реализаций языка Ruby, то увидите, что хоть в языке и есть "пустой объект" ("Nil" или "Null" - не помню уже), но физически он реализован в виде статической переменной языка си с определенным значением...

    не выделяйте память под пустые объекты сами, или перегрузите malloc (оператор new вроде вызывает malloc, хотя лучше проверить, посмотрев в исходниках) из CRT таким образом, чтобы он не выделял память меньшую 2 байтов, хотя это полный бред)))

    таблица виртуальных функций вроде идет в памяти перед данными класса... размер увеличивается на (n * sizeof(void*)), где n - количество виртуальных методов...
     
  16. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Rel
    Наивное заблуждение. В самом объекте хрпнится только один указатель на таблицу виртуальных методов класса, а сама эта таблица представлена в единственном экземпляре в статической памяти, т.к. было бы совершенно глупым расточительством дублировать одну и ту же таблицу в десятках или сотнях объектов одного и того же класса
     
  17. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    >_<

    http://www2.research.att.com/~bs/bs_faq2.html#sizeof-empty
     
  18. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Rel
    Имелось ввиду стандартизация конкретного размера, а так да, размер должен быть.

    cupuyc
    А вот это кстати не обязательно, компилятор может и убрать переменную.
     
  19. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    Booster, мдя.. любопытно:
    Код (Text):
    1. struct true_type {};
    2. struct false_type {};
    3.  
    4. template <bool b>
    5. struct bool_type {};
    6.  
    7. template <>
    8. struct bool_type<false> { static true_type value; };
    9.  
    10. true_type bool_type<false>::value;
    11.  
    12. template <>
    13. struct bool_type<true> { static false_type value; };
    14.  
    15. false_type bool_type<true>::value;
    16.  
    17. template <typename t> struct is_pointer { static const bool value = false; };
    18. template <typename t> struct is_pointer<t*> { static const bool value = true; };
    19.  
    20. int func(true_type ptr)
    21. {
    22.   return 2;
    23. }
    24.  
    25. int func(false_type ptr)
    26. {
    27.   return 10;
    28. }
    29.  
    30. int main()
    31. {
    32.   return func(bool_type<is_pointer<char*>::value>::value) +
    33.     func(bool_type<is_pointer<int>::value>::value);
    34. }
    получаем:
    Код (Text):
    1. .
    2. text:00401000 ; int __cdecl main(int argc, const char **argv, const char *envp)
    3. .text:00401000 _main           proc near               ; CODE XREF: ___tmainCRTStartup+10Ap
    4. .text:00401000                 mov     eax, 0Ch
    5. .text:00401005                 retn
    6. .text:00401005 _main           endp
     
  20. cupuyc

    cupuyc New Member

    Публикаций:
    0
    Регистрация:
    2 апр 2009
    Сообщения:
    763
    Ещё более любопытно:

    Код (Text):
    1. template <int a, int n> struct pow { static const int value = a * pow<a, n - 1>::value; };
    2. template <int a> struct pow<a, 0> { static const int value = 1; };
    3.  
    4. int main()
    5. {
    6.   return pow<-1, 1000>::value;
    7. }
    Студия кидает необработанный эксепшн, gcc зацикливается :)))