Подтвердить что ты не робот

С++ Как распределить память динамически на стеке?

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

4b9b3361

Ответ 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;
}

Ответ 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, которые могут использовать полиморфные распределители без изменения типа контейнера.

Вы также можете рассмотреть: