оставить в стеке или положить в кучу? - PullRequest
3 голосов
/ 17 июля 2011

Бывает, что функция использует локальный буфер для подготовки некоторого блока данных ограниченного размера и передачи его другой функции, например:

void foo()
{
  char buffer[MAX_SIZE];
  size_t size = write_fancy_things(buffer);
  bar(buffer, size);
}

Однако, в зависимости от значения MAX_SIZE,Вы можете быть обеспокоены тем, что съели бы слишком много стека и заменили код на что-то похожее на следующий пример (но, надеюсь, с большей осторожностью относительно управления памятью):

void foo()
{
  static char *buffer = new char[MAX_SIZE]; 
  size_t size = write_fancy_things(buffer);
  bar(buffer, size);
}

В общем случае эти две функции должны работать следующим образом:так же.Однако в первом примере, если MAX_SIZE слишком велико, мы с большей вероятностью достигнем предела стека.Использование больших значений может быть хорошо, если вы знаете, где используется функция, но иногда это не так.

Во втором примере мы имеем дело с дополнительным косвенным обращением, и буфер более подвержен ошибкам кэша ЦП, что может быть в том случае, если foo лежит на критическом пути с низкой задержкой, и мы ожидаем, что затраты на подготовкув большинстве случаев размер буфера будет очень низким.

Какой размер вы считаете слишком большим для размещения в стеке?Кроме того, есть ли какое-либо наказание за размещение большого блока данных в стеке, но с использованием только его небольшой части?

РЕДАКТИРОВАТЬ: write_fancy _things это просто синоним высказывания * I 'm записывает некоторые данные в буфер размером от 1 до MAX_SIZE *.Второй пример foo можно представить как метод класса, а статический указатель - как член класса, размещенный в конструкторе.Я просто, вероятно, упростил вещи, но не хотел вводить больше сложности, чем нужно, и сосредоточиться на проблемах стека.

Ответы [ 4 ]

4 голосов
/ 17 июля 2011

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

Стиль ужасен. Если write_fancy_things использует только X много байтов, а X неизвестно во время компиляции, тогда динамически выделяйте X байтов. Не выделяйте некоторый ожидаемый максимальный размер в стеке и не используйте статический буфер большего предполагаемого максимального размера. Используйте вектор правильного типа, измените его размер до соответствующего размера, а затем используйте этот буфер.

2 голосов
/ 17 июля 2011

Штраф за размещение данных в стеке отсутствует, поскольку вы просто уменьшаете указатель стека.

Размер стека можно изменить с помощью утилит ОС, поэтому я не буду беспокоиться о больших размерах до 1 МБ.

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

1 голос
/ 17 июля 2011

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

0 голосов
/ 17 июля 2011

Если при столкновении с границей кадра возникла проблема (потому что MAX_SIZE был слишком большим), преобразуйте в std :: vector

void foo()
{
  std::vector<char> buffer(MAX_SIZE);
  size_t size = write_fancy_things(&buffer[0]);
  bar(&buffer[0], size);
}

Если говорить прямо, ваша версия не является стартовой.

...