Учитывая std::vector, размер и емкость которого могут быть произвольными, как лучше всего изменить его размер на 0 и емкость как минимум на N (заданное число)?
Моя прямая идея:
void f(vector<int> &t, int N)
{
t.clear();
t.reserve(N);
}
но я заметил это
A reallocation is not guaranteed to happen, and the vector capacity is not guaranteed to change(when std::vector::clear is called).
Итак, мне интересно, как избежать перераспределения, когда исходная емкость больше заданного N?
цитируемая вами часть относится к std::vector::clear(). Однако ваш звонок в std::vector::reserve() должен гарантировать изменение емкости вектора и перераспределение (если N>t.size())
Нет возможности гарантировать уменьшать емкость (даже vector::shrink_to_fit).
Цитата из "cplusplus.com/reference/vector/vector/clear", поэтому, когда исходная емкость> = N, я боюсь, что std :: vector :: clear сделает ненужное перераспределение
cplusplus.com - дерьмо
@ Jarod42 извините, ссылка - cplusplus.com/reference/vector/vector/clear. поэтому этот подход может вызвать перераспределение, даже если емкость> = N, что для меня плохо.
@ M.M shrink_to_fit - это противоположность тому, о чем, по-видимому, просит los.





what's the best practice to change its size to 0 and capacity to N(a given number)? My direct idea is: ...
Ваше прямое представление правильное и самый простой вариант. reserve, чтобы быть педантичным, изменяет емкость на больше или, равную заданному числу; не гарантируется, что они будут равны (но все реализации, которые я тестировал, выделяют точно заданную сумму, если предыдущая емкость была меньше).
So I'm wondering how to avoid reallocating when the origin capacity is larger than the given N?
Используя реализацию стандартной библиотеки, которая не освобождает память при вызове clear (т.е. любая стандартная соответствующая реализация, как указано в ответе здесь).
Другой подход к гарантии (хотя, похоже, в этом нет необходимости, поскольку вышеупомянутое должно быть гарантировано, несмотря на слабую формулировку на cplusplus.com) без перераспределения (в случае N > t.capacity()): поскольку вектор содержит простые целые числа, и вы, похоже, знать, сколько элементов будет (как вы знаете, чтобы зарезервировать), вы можете просто вызвать t.resize(N) (чтобы удалить лишние элементы в случае, если размер был больше), не очищая вектор, а затем перейти к перезаписи существующих элементов, а не к добавлению новых .
Конечно, это означает, что вы не сможете наблюдать количество перезаписанных элементов, поэтому этот подход применим не для всех вариантов использования. Это нормально, если вы просто хотите заполнить вектор простым циклом.
Возможно, вы захотите зарезервировать перед изменением размера, если новый размер может быть больше старого, и вы не хотите перераспределять. Это связано с тем, что большинство реализаций выделяют точную сумму в резерв (как я уже упоминал), но используют стратегию умножения при изменении размера (насколько мне известно, ни одно из этих действий не гарантируется, но реализации, которые я использовал, согласовывались с этим поведением).
Вы имеете ввиду соответствующий стандарту std::vector::clear() вместо битого?
@Deduplicator ох, это было в C++ 11?
Здесь нет C++ 03, но копаясь в упомянутом вопросе SO, нет, C++ 11 просто удалил ненужное требование для T, чтобы его можно было перемещать.
vector <int> - это только пример, на самом деле создание элемента дорого, поэтому я выберу первый вариант. Спасибо!
@los Если создание элементов дорогое, то второй подход будет быстрее (при условии, что присваивание еще не дороже), поскольку он повторно использует существующие элементы. Классы, с которыми вы бы не хотели этого делать, - это вещи, которые нельзя использовать повторно, и их необходимо уничтожить, чтобы логика программы оставалась нетронутой.
Примечание: этот ответ отвечает на вопросы:
the best way to make a std::vector capacity=N and size=0?
а также
what's the best practice to change its size to 0 and capacity to N(a given number)?
Изменение на «> = N» и добавление требования об избежании перераспределения было добавлено после публикации этого ответа.
Стандарт не предлагает никакого способа гарантированный для достижения этого. Но ваш лучший шанс:
t.clear();
t.shrink_to_fit();
t.reserve(N);
Второй вызов - рекомендуемые, чтобы уменьшить емкость, чтобы она соответствовала текущему размеру (который на тот момент был бы 0).
Альтернатива, которая может работать или не работать, опять же по усмотрению реализации:
t.swap( std::vector<int>{} );
t.reserve(N);
Конечно, в случае, если shrink_to_fit действительно уменьшает емкость, последний reserveдолжен перераспределяется. Как это помогает избежать перераспределения?
@ user2079303 Отредактировано для пояснения, вопрос был существенно изменен с момента публикации этого ответа
Вероятно, лучший способ - это ваш текущий код.
К сожалению, стандарт позволяет реализации иметь контейнеры, емкость которых может только расти. В этом случае ваш код будет гарантировать только то, что емкость равна по меньшей мере N. Перераспределение произойдет, если начальная емкость меньше N, и ничего не произойдет, если емкость больше N. Эти баллы гарантированы стандартом, потому что черновик 4659 для C++ 17 говорит в [vector.capacity] (выделите мой):
void reserve(size_type n);
...
3 Effects: A directive that informs a vector of a planned change in size, so that it can manage the storage allocation accordingly. After reserve(), capacity() is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value of capacity() otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument of reserve().
а также
void shrink_to_fit();
...
8 Effects: shrink_to_fit is a non-binding request to reduce capacity() to size(). [ Note: The request is non-binding to allow latitude for implementation-specific optimizations. —end note ] It does not increase capacity(), but may reduce capacity() by causing reallocation.
У вас нет возможности гарантировать, что емкость будет ровно N. Вместо этого ваш код гарантирует, что если начальная емкость больше N, она не изменится и перераспределения не произойдет.
Обновлено: это поведение стабильно, по крайней мере, с C++ 11 (черновик n3337)
Откуда эта цитата?