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

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

5 ответов


есть два важных понятия, чтобы понять в первую очередь:

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

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

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


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

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

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


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

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

идиома, которая требует динамических жизней,-это идиома pimpl.

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

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

  • объекты динамического размера (контейнеры)
  • обработка неполных типов (см. Pimpl-идиома)
  • легко ли типа

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


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

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


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

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

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

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