Есть ли способ выделить память на стек вместо кучи? Я не могу найти хорошую книгу об этом, у кого здесь появилась идея?
С++ Как распределить память динамически на стеке?
Ответ 1
Используйте alloca()
(иногда называемый _alloca()
или _malloca()
), но будьте очень осторожны с этим - он освобождает память, когда вы выходите из функции, а не когда вы выходите из области видимости, поэтому вы быстро взорветесь, если вы используйте его внутри цикла.
Например, если у вас есть такая функция, как
int foo( int nDataSize, int iterations )
{
for ( int i = 0; i < iterations ; ++i )
{
char *bytes = alloca( nDataSize );
// the memory above IS NOT FREED when we pass the brace below!
}
return 0;
} // alloca() memory only gets freed here
Затем alloca() будет выделять дополнительные байты nDataSize каждый раз в цикле. Ни один из байтов alloca() не освобождается, пока вы не вернетесь из функции. Итак, если у вас nDataSize
1024 и iterations
8, вы выделите 8 килобайт перед возвратом. Если у вас nDataSize
= 65536 и iterations
= 32768, вы выделите в общей сложности 65536 × 32768 = 2 147 483 648 байт, что почти наверняка nDataSize
к nDataSize
стека и возникновению сбоя.
anecdote: Вы можете легко попасть в неприятности, если будете писать после конца буфера, особенно если вы передаете буфер в другую функцию, и эта подфункция имеет неверное представление о длине буфера. Однажды я исправил довольно забавную ошибку, когда мы использовали alloca()
для создания временного хранилища для рендеринга глифа шрифта TrueType перед отправкой его в память GPU. Наша библиотека шрифтов не учитывала диакритический знак в шведском символе Å при расчете размеров глифов, поэтому она указала нам выделить n байтов для хранения глифа перед рендерингом, а затем фактически отрисовала n + 128 байт. Дополнительные 128 байтов записываются в стек вызовов, перезаписывая адрес возврата и вызывая действительно болезненный недетерминированный сбой!
Ответ 2
Поскольку он помечен C++, обычно вы просто объявляете нужные объекты в правильной области видимости. Они размещаются в стеке и гарантированно освобождаются при выходе из области. Это RAII и критическое преимущество C++ над C. Никаких malloc
или new
s, и особенно никаких alloca
, не требуется.
Ответ 3
Вы можете объявить локальное char[1024]
или любое количество байтов, которое вы хотите (до точки), затем взять адрес локального для указателя на этот блок памяти в стеке. Не совсем динамично, но при необходимости вы можете завершить эту память с помощью своего собственного менеджера памяти.
Ответ 4
Статья обсуждает динамическое распределение памяти
Мы можем динамически распределять пространство переменной длины в стеке использование функции _alloca. Эта функция выделяет память из стека программ. Он просто берет количество байтов, которые нужно выделить, и возвращает void * в выделенное пространство так же, как вызов malloc. Эта выделенная память будет автоматически освобождается при выходе функции.
Таким образом, его не нужно явно освобождать. Нужно иметь в виду размер выделения здесь, так как может возникнуть исключение. стек для таких вызовов может использоваться обработка исключений переполнения. В случае исключение можно использовать
_resetstkoflw()
для его восстановления назад.Таким образом, наш новый код с
_alloca
будет:int NewFunctionA() { char* pszLineBuffer = (char*) _alloca(1024*sizeof(char)); ….. // Program logic …. //no need to free szLineBuffer return 1; }
Ответ 5
Смотрите _malloca
.
Ответ 6
Если/если С++ позволяет использовать (нестатические) значения const
для границ массива, это будет проще.
На данный момент лучший способ, который я знаю, - это рекурсия. Есть всевозможные умные трюки, которые можно сделать, но самый легкий, о котором я знаю, заключается в том, чтобы ваша программа объявляла массив фиксированного размера и заполняла и работала над тем, что у него есть. Когда это будет сделано, если ему нужно больше места для завершения, он называет себя.
Ответ 7
Вы можете использовать BDE библиотеку С++, например
const int BUFFER_SIZE = 1024;
char buffer[BUFFER_SIZE];
bdlma::BufferedSequentialAllocator allocator(buffer, BUFFER_SIZE);
bsl::vector<int> dataVector(&allocator);
dataVector.resize(50);
BDE предоставляет комплексные параметры распределителя наряду с коллекциями, такими как bsl:: vector, которые могут использовать полиморфные распределители без изменения типа контейнера.
Вы также можете рассмотреть: