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

Лучше ли использовать переменные кучи или стека?

У меня была дискуссия с другом некоторое время назад. Он опытный пользователь С++, и я не являюсь опытным пользователем С++. Он сказал мне, что я должен стремиться использовать переменные кучи, то есть:

A* obj = new A("A");

в отличие от:

A obj("A");

Помимо того, что использование указателей было приятным и гибким, он сказал, что лучше положить вещи в кучу, а не в стек (что-то о стеке меньше кучи?). Это правда? Если да, то почему?

Изменить: я сделал оговорку в том, что мой друг сообщил о переменных стека. Он рекомендовал переменные кучи.

Edit2: Я знаю о проблемах со временем жизни. Предположим, что я управлял временем жизни этих переменных соответствующим образом. (т.е. единственными критериями, вызывающими озабоченность, являются хранилище кучи и стека без каких-либо проблем с продолжительностью жизни)

4b9b3361

Ответ 1

В зависимости от контекста нам нужно использовать кучу или стек. Каждый поток получает стек, а поток выполняет команды путем включения функций. Когда вызывается функция, переменные функции переносятся в стек. И когда функция возвращает откат стека, а память исправляется. Теперь существует ограничение по размеру для локального стека потока, оно варьируется и может быть изменено в некоторой степени. Учитывая это ограничение, если каждый объект создается в стеке, а объект требует большой памяти, тогда стек может быть исчерпан, что приводит к ошибке stackoverflow. Кроме того, если объект должен быть доступен несколькими потоками, тогда хранение такого объекта в стеке не имеет смысла.

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

С++ 11 представляет интеллектуальные указатели (общие, уникальные), чтобы упростить управление памятью с помощью кучи. Фактически указанный объект находится в куче, но является инкапсуляцией с помощью умного указателя, который всегда находится в стеке. Следовательно, когда откаты стека во время возврата функции или во время исключения деструктор интеллектуального указателя удаляет фактический объект в куче. В случае общего указателя счетчик ссылок поддерживается и фактический объект удаляется, когда счетчик ссылок равен нулю. http://en.wikipedia.org/wiki/Smart_pointer

Ответ 2

Столбец должен быть предпочтен куче, так как выделяемые стеки переменные являются автоматическими переменными: их уничтожение выполняется автоматически, когда программа выходит из контекста. p >

Фактически, продолжительность жизни объекта, созданного в стеке и в куче, различна:

  • Локальные переменные функции или кодового блока {} (не выделенные новым), в стеке. Они автоматически уничтожаются, когда вы возвращаетесь из этой функции. (их деструкторы называются и их память освобождается).
  • Но если вам нужно что-то, что нужно использовать вне функции, вам придется выделять кучу (используя новую) или возвращать копию.

Пример:

 void myFun()
 {
   A onStack; // On the stack
   A* onHeap = new A(); // On the heap
   // Do things...

 } // End of the function onStack is destroyed, but the &onHeap is still alive

В этом примере onHeap по-прежнему будет выделяться память при завершении функции. Таким образом, если у вас нет указателя на onHeap где-то, вы не сможете удалить его и освободить память. Это утечка памяти, так как память будет потеряна до конца программы.

Однако, если вы должны были вернуть указатель на onStack, так как onStack был уничтожен при выходе из функции, использование указателя может привести к поведению undefined. При использовании onHeap все еще отлично.

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

Ответ 3

Всегда лучше избегать использования нового как можно больше в С++.
Однако есть моменты, когда вы не можете этого избежать.
Например:
Желание переменных существовать вне их областей.

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

Ответ 4

Нет общих правил относительно использования выделенных стека и переменных, выделенных кучей. Есть только рекомендации, в зависимости от того, что вы пытаетесь сделать.

Вот некоторые плюсы и минусы:

Распределение кучи:

Плюсы:

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

Минусы:

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

Распределение стека:

Плюсы:

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

Минусы:

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

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

В конце концов, это зависит от того, что нужно вашему приложению.

Ответ 5

Ответ не такой четкий, как некоторые заставляют вас поверить.

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

  • неизвестный размер во время компиляции
  • extensible (контейнеры используют распределение кучи внутри)
  • большие объекты

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

Лично я использую следующее руководство:

  • локальные объекты выделяются автоматически
  • локальные массивы откладываются до std::vector<T>, которые внутренне распределяют их динамически

он послужил мне хорошо (это, очевидно, просто анекдотические данные).

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

Ответ 6

С++ не упоминает кучу или стек. Что касается языка, то они не существуют/не являются отдельными вещами.

Что касается практического ответа - используйте то, что лучше всего работает - вам нужно быстро - вам нужны гарантии. Приложение A может быть намного лучше со всем, что есть в куче, приложение B может фрагментировать память ОС, так что он убивает машину - нет правильного ответа: - (

Ответ 7

Проще говоря, не управляйте своей собственной памятью, если вам не нужно.;)

Ответ 8

Stack = Статические данные, выделенные во время компиляции. (не динамический)

Куча = Дьянамические данные, выделенные во время выполнения. (Очень динамичный)

Хотя указатели находятся в стеке... Эти указатели прекрасны, потому что они открывают двери для динамического, спонтанного создания данных (в зависимости от того, как вы кодируете свою программу).

(Но я просто дикарь, так почему это важно, что я говорю)