Когда класс должен быть выделен в стеке вместо кучи

В прошлом, когда мне нужно было создать экземпляр класса, я использовал бы новый, чтобы выделить его в кучу (кроме классов stl и математических классов, таких как vec3 и mat4).

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

В прошлом я всегда дефолтировал выделение в куче и использовал только стек в определенных случаях, однако теперь мне интересно, было бы лучше по умолчанию выделять в стеке и использовать только кучу, когда

  • действительно нужен указатель (т.е. время жизни объекта, чтобы переместить область декларации)
  • класс или массив слишком большой для стека
  • Наследование требует его (абстрактный базовый класс/интерфейс)
  • что-то еще?

Что также поднимает вопрос: насколько большой класс слишком большой (грубо), чтобы разумно выделить в стеке? (предполагая, что мы работаем, как минимум, с смартфонами, и подходим к высокопроизводительным настольным компьютерам). Я просто неохотно беспокоюсь о ограничениях размера стека? (возможно, до тех пор, пока мы не говорим о больших массивах, и ни один класс не будет близок к килобайту)

Ответ 1

Я предпочитаю выделять в стеке по двум причинам. Во-первых, при прочих равных условиях он быстрее, чем куча. Кроме того, освобождение происходит автоматически, мне не нужно запоминать его delete (конечно, есть auto_ptr и такие, чтобы помочь с этим).

действительно нужен указатель

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

класс или массив слишком большой для стека

Только для действительно больших вещей это должно иметь значение. Вероятно, у вас есть 1 МБ стека, поэтому перед проблемой возникает 1000 объектов 1 КБ.

Наследование требует его

Почему?

что-то еще?

Срок службы, требуемый для объекта, больше, чем срок службы фрейма стека. Это основная причина для размещения в куче.

Ответ 2

Ваше поведение по умолчанию должно быть:

Если срок службы объекта соответствует определенной области

т.е. легко определяется во время компиляции

то это должен быть объект продолжительности автоматического хранения (например, стек)

Если срок жизни объекта определяется во время выполнения и выходит за пределы текущей области

Затем это должен быть объект динамической памяти (куча вроде)

Примечание. Все объекты с динамической памятью должны контролировать свою продолжительность, упаковывая их в соответствующий класс RAII. Обычно это означает: для отдельных объектов - умный указатель, а несколько объектов - в контейнере.

Я ненависть, чтобы видеть, что вещи определяются как куча стека Vs. Поскольку это не передает реальную семантику ситуации.

 int x;       // its on the stack
 struct X
 {
     int x;   // Is this a stack or heap object?
 }            // It depends on its parent.


 // But in both cases it is an automatic storage duration object.
 // In both cases the lifespan are well defined.
 //     The first is defined by the scope it is declared within.
 //     The second is defined by the lifespan of its parent.

Вы должны думать об объектах автоматической/динамической "продолжительности хранения". Это передает правильную семантику языка.

Обратите внимание, что существуют два других типа переменных, которые образуют четыре разных типа переменных. автоматические/динамические/статические/потоковые объекты хранения.

Ответ 3

Когда класс должен быть выделен в стеке вместо кучи?

По возможности, а не большие неудобства. Будут исключения, но чтобы ответить на ваш вопрос как общее правило: при создании экземпляра new/new[] следует вводить менее одного процента времени.


действительно нужен указатель (т.е. время жизни объекта, чтобы переместить область декларации)

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

класс или массив слишком большой для стека

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

Наследование требует его (абстрактный базовый класс/интерфейс)

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

что-то еще?

Нет


Причины:

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

Ответ 4

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