Как определить, должен ли объект быть в стеке или нет? - PullRequest
7 голосов
/ 06 марта 2009

Я искал эмпирическое правило для размещения объектов в стеке или куче в C ++. Я нашел много обсуждений здесь на SO. Многие люди говорили, что речь идет о времени жизни объекта. Если вам нужно больше времени жизни, чем объем функции, поместите его в кучу. Это имеет смысл.

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

У меня есть следующие вопросы,

  1. Как определить, объект большой или нет?
  2. Каким будет максимальный размер стека? Каждая ОС будет иметь разный размер стека?
  3. У меня есть класс-оболочка, который упаковывает vector<string>. В нем будет около 100 предметов. Будет ли переполнение стека, если я выделю этот класс в стек? Я попробовал это, но это сработало отлично. Не уверен, что я делаю что-то не так.

Ответы [ 6 ]

10 голосов
/ 06 марта 2009

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

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

std::vector<int> myInts;
std::string myString;
SomeOther Class;

// this memory must come from the heap, there's no way it
// can now be allocated on the stack since there are other
// objects and these parameters could be variable
myString = "Some String";
myInts.reserve(256);

Если вы не используете рекурсивную функцию, вы можете поместить несколько килобайт данных в стек без особого беспокойства. Размеры стеков контролируются программой (а не ОС), и значение по умолчанию обычно колеблется от 32 КБ до 1 МБ. Большинство настольных программ выпускается в диапазоне 1 Мб.

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

Если объекты являются локальными для функции, поместите их в стек. Если не положить их в кучу.

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

4 голосов
/ 06 марта 2009

Согласно MSDN размер стека по умолчанию равен 1 МБ. (Это для Мсдев очевидно).

Как видно из статьи, вы можете изменять размер стека во время компиляции с помощью флага / F.

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

3 голосов
/ 06 марта 2009

Единственный способ выделить большие объекты в стеке - это задействовать массив старого стиля в какой-то момент. Например:

void f() {
   char a[1000000];    // big object on the stack
}

struct A {
   char c[1000000];
};

void g() {
   A a;      // another big object on the stack
}

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

void h() {
   std::string s( 100000 );
}

Вышеуказанное выделяет в стеке несколько байтов для указателей, информации о размере и т. Д., А затем выделяет фактическое хранилище в куче.

Так что перестань беспокоиться! Вы, вероятно, делаете все правильно!

1 голос
/ 06 марта 2009

1. Как определить объект большой или нет?

Используйте "sizeof"

class c {
  std::vector<std::string> s;
};

int size = sizeof (c);

На моей машине "размер" составляет 16 байт.

2. Каким будет максимальный размер стека? Каждая ОС будет иметь разный размер стека?

Вы не можете сказать, но это определенно не хорошее место для распределения масс данных.

3. У меня есть класс-обертка, который оборачивает вектор. В нем будет около 100 предметов. Будет ли переполнение стека, если я выделю этот класс в стек? Я попробовал это, но это сработало отлично. Не уверен, что я делаю что-то не так.

Нет. std :: vector выделяет 100 элементов в куче.

1 голос
/ 06 марта 2009

Еще один момент, который я упомяну, заключается в том, что, поскольку vector<> должен иметь возможность изменять свой размер, если он становится достаточно большим (см. Ниже), он должен использовать кучу для хранения содержащихся в нем объектов, даже если сам vector<> объявлен как переменная стека.

[EDIT] Как указывает Мотти в комментарии, вполне возможно, что vector<> резервирует небольшое количество пространства внутри выделенного им стека объекта в качестве оптимизации для небольших векторов. В этом случае работа с векторами, достаточно маленькими для размещения внутри этого пространства, не потребует выделения кучи. (Это заранее выделенное пространство должно быть достаточно маленьким, чтобы избежать потери пространства при работе с меньшими векторами.) Независимо от того, если вектор становится достаточно большим, ему потребуется (пере) размещение в куче.

1 голос
/ 06 марта 2009

Как определить, объект большой или нет?

Зависит от вашего компилятора / платформы. Нет Единого Истинного Предела. Компиляторы часто позволяют вам настроить это.

Каким будет максимальный размер стека? Каждая ОС будет иметь разный размер стека?

Зависит в основном как указано выше. Единственное, что у вас меньше контроля над настройкой.

У меня есть класс-обертка, который переносит вектор. В нем будет около 100 предметов. Будет ли переполнение стека, если я выделю этот класс в стек? Я попробовал это, но это сработало отлично. Не уверен, что я делаю что-то не так.

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

Хорошая идея - пройтись по отладчику и посмотреть адреса стека - это в некоторой степени даст вам начало ширины. И документация.

...