Какие алгоритмы в библиотеке стандартных алгоритмов выделяются и есть ли способ указать, как происходит это распределение?
Я бы хотел больше использовать стандартные алгоритмы, но предъявляю довольно жесткие требования к управлению распределением памяти.
Есть ли исчерпывающий список, какие алгоритмы выделить?
Кроме того, есть ли способ контролировать, как происходит это распределение? Единственный вариант, переопределяющий глобальный новый? Это на самом деле работает, если ссылки статически? До C++17 казалось, что все выделения проходили через std::get_teorary_buffer() для выделения памяти, но это кажется устаревшим в C++17. Что заменяет это?
3 ответа
Похоже, что единственный способ получить контроль над распределением - это переопределить глобальное новое. Смотрите здесь, раздел "Глобальные замены"
http://en.cppreference.com/w/cpp/memory/new/operator_new
Так как это работает во время соединения, это означает, что каждый dll должен будет связать модуль перевода с переопределенным глобальным new / delete. Как именно это соответствует какой-либо конкретной стратегии распределения, вероятно, выходит за рамки этого вопроса.
Другие ответы здесь указывают, какие алгоритмы пытаются использовать временные.
stable_partition, stable_sort и inplace_merge
AFAIR ни один из стандартных алгоритмов не выделяет память, если:
- ваш пользовательский тип выделяет память во время копирования или перемещения, или
- ваш выходной итератор выделяет память во время присваивания значения - например
std::back_insert_iterator<>
Исправление:
Его используют следующие алгоритмы:
- stable_partition
- inplace_merge
- stable_sort
Кажется, что реальность такова, что реализация libstdC++ просто пытается выделить буфер, используя T::operator new
и делит размер выделения пополам, если new
call возвращает ноль, пока размер выделения не станет равным нулю.
template<typename _Tp>
pair<_Tp*, ptrdiff_t>
__get_temporary_buffer(ptrdiff_t __len, _Tp*)
{
const ptrdiff_t __max = numeric_limits<ptrdiff_t>::max() / sizeof(_Tp);
if (__len > __max)
__len = __max;
while (__len > 0)
{
_Tp* __tmp = static_cast<_Tp*>(::operator new(__len * sizeof(_Tp),
nothrow));
if (__tmp != 0)
return pair<_Tp*, ptrdiff_t>(__tmp, __len);
__len /= 2;
}
return pair<_Tp*, ptrdiff_t>(static_cast<_Tp*>(0), 0);
}
источник: https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.0/memory-source.html
Оказывается, что эта функция является спорной, так как Александр Степанов, оригинальный автор СТЛ, написал это как реализацию заполнителя, оставляя документацию, она никогда не должна идти в производство.
Излишне говорить, что это было, и с тех пор было в каждом порту STL.
Для непараллельных алгоритмов stable_partition
, stable_sort
, а также inplace_merge
это три, которые определенно попытаются получить дополнительную память, прибегая к менее эффективному алгоритму, если он не может этого сделать. Как именно они пытаются получить память, не уточняется.
Однако ничто в стандарте не говорит о том, что другие алгоритмы не могут пытаться выделить память просто так. Высококачественная реализация не должна, но если вам действительно нужно, чтобы она не выделялась, вы должны проверить реализацию самостоятельно.