Как определить, должен ли объект находиться в стеке или нет?
Я искал эмпирическое правило для выделения объектов в стеке или куче в C++. Я нашел много дискуссий здесь на SO. Многие говорили, что речь идет о времени жизни объекта. Если вам нужно больше времени жизни, чем область действия функции, поместите ее в кучу. В этом есть смысл.
но что меня смутило, так это то, что многие люди говорили, выделяют объекты в стек, если они маленькие. Если объекты большие, поместите их в кучу. Но никто из них не сказал, Как определить объект большой или нет?
У меня есть следующие вопросы,
- как определить объект большой или нет?
- какой будет максимальный размер стека? Каждая ОС будет иметь разный размер стека?
- у меня есть класс-обертка, который обертывает
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);
Если вы не находитесь в рекурсивной функции, которую вы можете разместить несколько килобайт данных в стеке без особого беспокойства. Размеры стека контролируются программой (а не ОС), и значение по умолчанию имеет тенденцию варьироваться от 32kb - 1mb. Большинство настольных программ поставляется в диапазоне 1mb.
отдельные объекты почти никогда не касается. В общем случае они будут либо достаточно малы для стека, либо будут выделяться изнутри из кучи.
если объекты являются локальными для функции поместить их в стек. Если не положить их на куча.
используйте кучу для больших буферов, которые вы выделяете для загрузки/сортировки / управления данными.
по данным MSDN размер стека по умолчанию равен 1 Мб. (Это для Msdev, очевидно).
Как вы можете видеть из статьи, вы можете изменить размер стека во время компиляции с флагом /F.
Я думаю, что ваше первое руководство по использованию стека против кучи довольно точно, с оговоркой, что если временная переменная области больше Мб, вставьте ее в кучу (и, вероятно, спросите, почему вы выделяете так много памяти в течение короткого периода времени в первое место).
единственный способ выделить большие объекты в стеке - это задействовать массив старого стиля в какой-то момент. Например:
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 );
}
выше выделяет несколько байтов в стеке для указателей, информации о размере и т. д. а затем выделяет фактическое хранилище в куче.
Так что перестаньте беспокоиться! Ты, наверное, все делаешь правильно!
Как определить объект большой или нет?
зависит от вашего компилятора/платформы combo. Нет ни одного истинного предела. Компиляторы часто позволяют настроить это.
какой будет максимальный размер стека? Каждая ОС будет иметь разный размер стека?
зависит главным образом как выше. Единственное, что у вас меньше контроля над настройкой.
У меня есть класс-оболочка, которая окутывает вектор. Это будет около 100 наименований. Будет ли это переполнение стека, если я выделю этот класс стеку? Я попробовал, но получилось отлично. Не уверен, что делаю что-то не так.
будет работать до тех пор, пока общая потребность в памяти этой оболочки и других объектов в этом блоке не превышает размер кадра стека. Что в свою очередь зависит от средней строки sie.
хорошей идеей является шаг через отладчик и увидеть адреса стека-это даст вам начало ширины в некоторой степени. И документы.
1. Как определить объект большой или нет?
используйте "sizeof"
class c {
std::vector<std::string> s;
};
int size = sizeof (c);
на моей машине "размер" составляет 16 байт.
2. Каким будет максимальный размер стека? Каждая ОС будет иметь разный размер стека?
вы не можете сказать, но это определенно не хорошее место, чтобы выделить массивы данных.
3. У меня есть класс-оболочка, которая окутывает вектор. Это будет около 100 наименований. Будет ли это переполнение стека, если я выделю этот класс стеку? Я попробовал, но получилось отлично. Не уверен, что делаю что-то не так.
нет. std:: vector выделяет 100 элементов в куче.
еще один момент, который я упомяну, потому что vector<>
должен иметь возможность изменять размер, если он становится достаточно большим (см. ниже) это должны используйте кучу для хранения содержащихся в ней объектов, даже если vector<>
сам объявлен как переменная стека.
[EDIT] как указывает Мотти в комментарии, возможно, что vector<>
резервирует небольшое пространство внутри объекта, выделенного стеком, в качестве оптимизации для небольших векторов. В этом случае, работая с векторы, достаточно маленькие, чтобы поместиться внутри этого пространства,не потребуют выделения кучи. (Это предварительно выделенное пространство должно быть довольно небольшим, чтобы избежать потери места при работе с меньшими векторами.) Независимо от того, если вектор растет достаточно большим, он потребует (повторного)выделения в куче.