Зачем мне нужен std:: get_temporary_buffer?

С какой целью я должен использовать std::get_temporary_buffer? Стандарт говорит следующее:

Получает указатель на хранилище, достаточный для хранения до n соседних объектов T.

Я думал, что буфер будет выделен в стеке, но это не так. Согласно стандарту С++ этот буфер фактически не является временным. Какие преимущества имеет эта функция для глобальной функции ::operator new, которая также не создает объекты. Правильно ли, что следующие утверждения эквивалентны?

int* x;
x = std::get_temporary_buffer<int>( 10 ).first;
x = static_cast<int*>( ::operator new( 10*sizeof(int) ) );

Эта функция существует только для синтаксического сахара? Почему существует temporary в его имени?


Один вариант использования был предложен в Dr. Dobb Journal, 1 июля 1996 г. для реализации алгоритмов:

Если буфер не может быть выделен или если он меньше запрошенного, алгоритм все еще работает правильно, он просто замедляется.

Ответ 1

Stroustrup говорит в "Язык программирования С++" (§19.4.4, SE):

Идея состоит в том, что система может содержать несколько буферов фиксированного размера, готовых к быстрому распределению, так что запрос пространства для n объектов может дать пространство больше, чем n. Тем не менее, это может также дать меньше, поэтому один из способов использования get_temporary_buffer() заключается в том, чтобы оптимистично просить много, а затем использовать то, что будет доступно.
[...] Поскольку get_temporary_buffer() является низкоуровневым и может быть оптимизирован для управления временными буферами, он не должен использоваться в качестве альтернативы новому или allocator:: allocate() для получения более длительного хранения.

Он также начинает введение в две функции с помощью:

Алгоритмы часто требуют, чтобы временное пространство выполнялось приемлемо.

... но, похоже, не дает определения временного или долгосрочного в любом месте.

An анекдот в "От математики к универсальному программированию" упоминает, что Степанов предоставил фальшивую замену заполнителя в оригинальной конструкции STL:

К своему удивлению, он обнаружил годы спустя, что все основные поставщики, предоставляющие STL-реализации, все еще используют эту ужасную реализацию [...]

Ответ 2

Пользователь стандартной библиотеки Microsoft говорит следующее (здесь):

  • Не могли бы вы объяснить, когда использовать 'get_temporary_buffer'

Он имеет очень специализированную цель. Обратите внимание, что он не бросает исключения, такие как new (nothrow), но он также не создает объекты, в отличие от нового (nothrow).

Он используется внутри STL в таких алгоритмах, как stable_partition(). Это происходит, когда есть волшебные слова, такие как N3126 25.3.13 [alg.partitions]/11: stable_partition() имеет сложность "Максимум (последний - сначала) * log (last-first) swaps, но только линейное число свопов, если имеется достаточная дополнительная память." Когда волшебные слова "если есть достаточно дополнительной памяти", STL использует get_temporary_buffer() для попытаться приобрести рабочее пространство. Если это возможно, то он может реализовать алгоритм более эффективно. Если он не может, поскольку система запущена опасно близкие к памяти (или диапазоны задействованы огромные), алгоритм может вернуться к более медленной технике.

99.9% пользователей STL никогда не должны знать о get_temporary_buffer().

Ответ 3

В стандарте указано, что он выделяет хранилище для элементов до n. Другими словами, ваш пример может вернуть буфер, достаточно большой для 5 объектов.

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

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

Ответ 4

ptrdiff_t            request = 12
pair<int*,ptrdiff_t> p       = get_temporary_buffer<int>(request);
int*                 base    = p.first;
ptrdiff_t            respond = p.sencond;
assert( is_valid( base, base + respond ) );

ответ может быть меньше запроса.

size_t require = 12;
int*   base    = static_cast<int*>( ::operator new( require*sizeof(int) ) );
assert( is_valid( base, base + require ) );

фактический размер базы должен быть больше или равен требуемому.

Ответ 5

Возможно (просто догадка) это имеет какое-то отношение к фрагментации памяти. Если вы в значительной степени продолжаете выделять и освобождать временную память, но каждый раз, когда вы это делаете, вы выделяете некоторую долговременную память после выделения темпа, но до ее освобождения вы можете получить фрагментированную кучу (я думаю).

Таким образом, get_temporary_buffer может быть предназначен для большего объема памяти, который выделяется один раз (возможно, есть много чанков, готовых принять несколько запросов), и каждый раз, когда вам нужна память, вы просто получаете один из кусков. Таким образом, память не фрагментируется.

Ответ 6

С какой целью я должен использовать std::get_temporary_buffer?

Функция устарела на С++ 17, поэтому правильный ответ теперь "не имеет смысла, не используйте его".