Изменение размера вектора std::с помощью вставки перемещения и вставки копирования

#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. Хорошо, мы можем просто оставить комментарии здесь, тогда, когда это не станет достаточно ясным, они помогут 🙂