#c #stdvector #move-semantics
Вопрос:
В разделе vector.capacity стандарта C он определяет две перегрузки для resize()
. (см. также https://en.cppreference.com/w/cpp/container/vector/resize)
Эта перегрузка требует, чтобы тип T был MoveInsertable
и DefaultInsertable
:
constexpr void resize(size_type sz);
Другая перегрузка требует, чтобы тип T был CopyInsertable
:
constexpr void resize(size_type sz, const Tamp; c);
Мой вопрос в том, почему вторая перегрузка не пытается перейти от существующих значений к старому вектору, а затем скопировать и вставить новые значения из предоставленного c
аргумента. Разве это не было бы более эффективно?
Комментарии:
1. Он может перейти от старого к новому (вероятно, сделает это, если сможет), но значение заполнения (
c
) должно быть скопировано, поэтомуT
должно бытьCopyInsertable
.2. встречный вопрос: Как часто вы можете перемещаться,
c
прежде чем он станет непригодным для использования, потому что он перемещен из объекта в неопределенное состояние?3. Кто сказал, что это не так…? Это вполне может быть сделано для существующих элементов. Это невозможно из-за значения заполнения по уже приведенным очевидным причинам. Неясно, в чем на самом деле заключается вопрос.
4. при повторном чтении я больше не уверен, правильно ли я понял вопрос. Вы спрашиваете об элементах, которые уже присутствовали в векторе до изменения размера? Я ожидал бы, что они будут перемещены, когда это возможно, но это ортогонально тому, как создаются новые элементы
5. в какой-то момент
resize(size_type sz, ??? c)
нужно сделать копию (еслиnew size == old size 1
только ), вот почему это требуетсяCopyInsertable
, что не исключает, что он также будет использовать более слабые ограничения, когда они будут применяться
Ответ №1:
Я согласен, что вторым параметром может быть ссылка на значение rvalue — это сохраняет одну копию, когда она впоследствии копируется из первого вновь добавленного элемента. Я предполагаю, что вы имеете в виду что-то вроде этого:
std::vector<LargeObject> v;
// ...
LargeObject obj = setupLotsOfResources();
// Now do 1 move and 9 copies instead of 10 copies
v.resize(10, std::move(obj));
Однако я бы счел это крайним случаем, и работа со ссылками rvalue, которые используются для построения 1 перемещения и N-1 копий, является довольно запутанным API. Поскольку вы можете свободно использовать std::vector
API с тем, что уже есть, так что для приведенного выше примера у вас будет 1 перемещение и N-1 копия, я считаю, что обоснование существующей подписи функции заключается в простоте использования и простой подписи, которая не требует большого изучения спецификаций, чтобы понять, что она делает.
Комментарии:
1. я также предполагал, что это компромисс между этой копией и четкостью интерфейса.
void resize(size_type sz, Tamp;amp; c);
может быть легко неправильно понято как отсутствие копий2. Э-э, да, это именно то, что я пытался выразить. Кажется, в ответе не все ясно
3. ноно, все ясно. Просто я не был на 100% уверен, что это то, что вы имеете в виду, хотя я также не знал бы, к чему еще относится этот последний абзац, если бы не это
4. Хорошо, мы можем просто оставить комментарии здесь, тогда, когда это не станет достаточно ясным, они помогут 🙂