Как определить, должен ли объект быть в стеке или нет?

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

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

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

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

6 ответов

Решение

Во-первых, векторы (и все классы контейнеров 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 Мб.

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

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

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

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

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

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

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

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 );
}

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

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

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

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

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

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

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

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

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

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

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

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

int size = sizeof (c);

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

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

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

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

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

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

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

Другие вопросы по тегам