Лучше ли использовать переменные кучи или стека?
У меня была дискуссия с другом некоторое время назад. Он опытный пользователь С++, и я не являюсь опытным пользователем С++. Он сказал мне, что я должен стремиться использовать переменные кучи, то есть:
A* obj = new A("A");
в отличие от:
A obj("A");
Помимо того, что использование указателей было приятным и гибким, он сказал, что лучше положить вещи в кучу, а не в стек (что-то о стеке меньше кучи?). Это правда? Если да, то почему?
Изменить: я сделал оговорку в том, что мой друг сообщил о переменных стека. Он рекомендовал переменные кучи.
Edit2: Я знаю о проблемах со временем жизни. Предположим, что я управлял временем жизни этих переменных соответствующим образом. (т.е. единственными критериями, вызывающими озабоченность, являются хранилище кучи и стека без каких-либо проблем с продолжительностью жизни)
Ответы
Ответ 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 = Статические данные, выделенные во время компиляции. (не динамический)
Куча = Дьянамические данные, выделенные во время выполнения. (Очень динамичный)
Хотя указатели находятся в стеке... Эти указатели прекрасны, потому что они открывают двери для динамического, спонтанного создания данных (в зависимости от того, как вы кодируете свою программу).
(Но я просто дикарь, так почему это важно, что я говорю)