Стек против кучи для фиксированного числа объектов, требующих глобальной области видимости - PullRequest
1 голос
/ 09 февраля 2012

Мне известно, что вопросы о стеке и куче задавались несколько раз, но я запутался в одном небольшом аспекте выбора способа объявления объектов в C ++.

Я понимаю, что куча - доступ с помощью оператора "new" - используется для динамического выделения памяти. Согласно ответу на другой вопрос о переполнении стека, «куча предназначена для хранения данных, где время жизни хранилища не может быть определено заранее». Стек быстрее, чем куча, и, кажется, используется для переменных локальной области видимости, то есть переменные автоматически удаляются, когда соответствующий раздел кода завершается. Стек также имеет относительно ограниченный объем доступного пространства.

В моем случае, до начала выполнения я знаю, что мне понадобится массив указателей ровно на 500 объектов определенного класса, и я знаю, что мне потребуется хранить указатели и объекты в течение всего времени выполнения. Куча не имеет смысла, потому что я заранее знаю, как долго мне понадобится память, и точно знаю, как мне будут нужны человеческие объекты. Стек также не имеет смысла, если он ограничен в объеме; Кроме того, я не знаю, может ли он содержать все мои объекты / указатели.

Как лучше всего подойти к этой ситуации и почему? Спасибо!

Ответы [ 7 ]

5 голосов
/ 09 февраля 2012

Объекты, размещенные в стеке в main(), имеют время жизни всего прогона программы, так что это вариант.Массив из 500 указателей имеет размер 2000 или 4000 байт в зависимости от того, имеют ли ваши указатели ширину 32 или 64 бита - если вы программируете в среде с ограниченным стеком, вы бы это знали (такие среды do существует: например, стеки режима ядра часто имеют размер 8192 байта или меньше всего ), поэтому я без колебаний помещу туда массив.

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

Если они слишком велики для стека, я бы серьезно подумал о создании глобальной переменной, которая бы представляла собой массив самих объектов.Основным недостатком этого является то, что вы не можете точно контролировать, когда они инициализируются.Если объекты имеют нетривиальные конструкторы, это, вероятно, будет проблемой.Альтернативой является выделение хранилища для объектов как глобальной переменной, инициализация их в соответствующей точке в main с использованием размещения new и явное обращение к их деструкторам при выходе.Это требует осторожности при наличии исключений;Я написал бы одноразовый класс RAII, который инкапсулировал работу.

4 голосов
/ 09 февраля 2012

Это не вопрос стека или кучи (точнее говоря, это не означает, что вы думаете в c ++: это просто структуры данных, такие как вектор, набор или очередь).Речь идет о продолжительности хранения .

Скорее всего, здесь вам понадобятся статическая длительность объектов, которые могут быть как глобальными, так и членами класса.Автоматические переменные, объявленные внутри функции main, также могут выполнять эту работу, если вы разрабатываете способ доступа к ним из другого кода.

Существует некоторая информация о различных сроках хранения C ++ (автоматическая, статическая,динамический) есть .Принятый ответ, однако, использует запутанную терминологию стека / кучи, но объяснение верное.

3 голосов
/ 09 февраля 2012

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

Хотя это правильно, оно также неполно.

Стек разворачивается, когда вы выходите из своей области видимости, поэтому, как вы сказали, использовать его для глобальных переменных области действия невозможно. Это, однако, где вы перестаете быть на правильном пути. Хотя вы знаете время жизни (или, точнее, scope , так как это самый важный фактор здесь), вы также знаете, что оно выше стекового фрейма , поэтому, учитывая только два варианта, вы ставите его в кучу.

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

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

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

2 голосов
/ 09 февраля 2012

Я думаю, что вы путаете использование стека (хранилище для локальных переменных и параметров) и данных с незаданной областью (статические переменные класса и данные, выделенные через new или malloc).Одним подходящим решением, основанным на вашем описании, будет статический класс, в котором ваш массив указателей объявлен как член статического класса.Это будет размещено в структуре, подобной куче (возможно, даже куче в зависимости от вашей реализации C ++).«быстрое и грязное» решение состояло бы в том, чтобы объявить массив как статическую переменную (в основном, глобальную переменную), однако это не лучший подход с точки зрения удобства обслуживания.

2 голосов
/ 09 февраля 2012

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

1 голос
/ 09 февраля 2012

Лучшая концепция: «Используйте стек, когда можете, и кучу, когда нужно».Я не понимаю, почему стек не сможет вместить все ваши объекты, если они не велики или если вы работаете с системой ограниченных ресурсов.Попробуйте стек, и если он не может с этим справиться, время, которое потребуется для выделения памяти в куче, может быть все сделано в начале выполнения программы и не будет значительной проблемой.

0 голосов
/ 09 февраля 2012

Если скорость не является проблемой или вы не можете позволить себе накладные расходы, вы должны засунуть объекты в std::vector.Если семантика копирования не определена для объектов, вы должны использовать std::vector из std::shared_ptr s.

...