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

Когда и почему объявлять переменные-члены в куче С++

Хорошо, поэтому я очень новичок в программировании на C++, и я искал пару дней для решительного ответа на это. КОГДА я должен объявлять переменные-члены в куче против стека? Большинство ответов, которые я нашел, касались других проблем, но я хочу знать, когда лучше использовать кучу для переменных-членов и почему лучше нагромождать элементы вместо их укладки.

4b9b3361

Ответ 1

Вначале есть два важных понятия:

  • Следует избегать мышления с точки зрения "кучи" и "стека". Это детали реализации вашего компилятора/платформы, а не языка. 1 Вместо этого подумайте о сроках жизни объекта: должно ли время жизни объекта соответствовать значению его "родителя" или если оно переживет его? Если вам нужно последнее, вам нужно будет использовать new (прямо или косвенно) для динамического выделения объекта.

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

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


<Суб > 1. В самом деле, стандарт С++ действительно не говорит о "куче" и "стеке". Их важно учитывать при оптимизации или вообще думать о производительности, но они в основном не имеют отношения к программной функциональности.

Ответ 2

Элементы-члены являются членами самого класса. Они ни на кучи или стека, или, вернее, они где-нибудь класс сам есть.

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

Ответ 3

Чтобы получить некоторую терминологию прямо: то, что вы называете heap и stack, описывает время жизни объектов. Первое означает, что время жизни dynamic, второе automatic и третье (которое вы не упоминаете) static.

Обычно вам понадобится dynamic время жизни объекта, когда он должен пережить область, в которой он был создан. Другим распространенным случаем является то, что вы хотите, чтобы он был разделен между разными родительскими объектами. Кроме того, динамическое время жизни также необходимо, когда вы работаете с дизайном, который сильно объектно-ориентирован (использует много полиморфизма, не использует значения), например. Qt.

Идиомой, требующей динамических времен жизни, является пимпловая идиома.

Большинство общих программных библиотек больше ориентированы на семантику ценности и ценности, поэтому вы не будете использовать динамическое связывание, так много и автоматическое время жизни станут намного более распространенными.

Есть также некоторые примеры, когда динамическое распределение требуется для более конкретных причин реализации:

  • объекты с динамическим размером (контейнеры)
  • обработка неполных типов (см. pimpl-idiom)
  • простая нулеустойчивость типа

Все это только общие рекомендации, и это необходимо решать в каждом конкретном случае. В общем, предпочитайте автоматические объекты по динамическим.

Ответ 4

Стек относится к call stack. В стеке вызовов хранятся вызовы функций, обратные адреса, параметры и локальные переменные. Вы используете стек памяти всякий раз, когда вы передаете параметр или создаете локальную переменную. Стек имеет только временное хранилище. Как только текущая функция выходит из области видимости, вы больше не имеете доступа к каким-либо переменным для параметров.

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

Ответ 5

Рассмотрим этот пример:

Вы реализуете связанный список с заголовком члена поля класса node.
Каждый node имеет член поля next. Если этот член типа node, а не Node * размер каждого node будет зависеть от количества узлов после него в цепочке.

Например, если в вашем списке 100 узлов, ваш руководитель будет огромным. Поскольку он содержит следующий node внутри себя, поэтому он должен иметь достаточный размер, чтобы удерживать его, а затем удерживает следующий и т.д. Таким образом, голова должна иметь достаточно места для удержания в ней 99 узлов в следующих 98 и так далее...

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