Подтвердить что ты не робот

Почему в С++ 11 была изменена подпись std::vector:: resize?

Каковы причины изменения в std::vector::resize из pre-С++ 11:

void resize( size_type count, T value = T() );

к совместимой форме С++ 11:

void resize( size_type count );
void resize( size_type count, const value_type& value);
4b9b3361

Ответ 1

Пункт C.2.12 Приложения C (Совместимость) к стандарту С++ 11 указывает:

Изменить: изменения подписи: resize

Обоснование: Производительность, совместимость с семантикой перемещения.

Влияние на оригинальную функцию: для vector, deque и list значение заливки, переданное для изменения размера, теперь передается ссылка вместо значения, и добавлена ​​дополнительная перегрузка размера. Действительный код С++ 2003 который использует эту функцию, может не скомпилироваться с этим Международным стандартом.

Старая функция resize() заключалась в копировании новых элементов из value. Это делает невозможным использование resize(), когда элементы вектора по умолчанию являются конструктивными, но не скопируемыми (вы можете захотеть переместить их позже). Это объясняет логику "Совместимость с семантикой перемещения".

Кроме того, это может быть медленным, если вы не хотите, чтобы какая-либо копия возникла, а только новые элементы, которые будут построены по умолчанию. Кроме того, параметр value передается по значению в версии С++ 03, что связано с накладными расходами ненужной копии (как упоминалось в шаблоне TemplateRex)). Это объясняет обоснование "производительности".

Ответ 2

Одна из причин заключается в том, что аргументы по умолчанию всегда передаются, то есть копируются в этом случае. Выполнение

 my_vector.resize(1000000) 

будет копировать 1 миллион объектов T.

В С++ 11 теперь у вас есть выбор между копированием созданного пользователем значения или элементов с добавлением по умолчанию (т.е. построения) на месте с помощью функции std::allocator_traits<Alloc>::construct(). Это позволяет изменять размер vector с помощью элементов, которые являются CopyInsertable, но не копируются.

Обратите внимание, что это изменение было сделано для всех контейнеров последовательностей, имеющих член resize() (vector, deque, forward_list и list), но не для std::string, у которого не было аргумент значения по умолчанию.

Обновить. Помимо приложения к текущему стандарту, приведенному в @AndyProwl, исходный отчет о дефектах от @HowardHinnant также уточняет:

Проблема с передачей T по значению заключается в том, что она может быть значительно дороже, чем передача по ссылке. Обратное также верно, однако, когда это правда, это обычно намного менее драматично (например, для скалярные типы).

Даже при наличии семантики перемещения, передавая этот параметр по значению может быть дорогостоящим. Рассмотрим, например, вектоp > :

std::vector<int> x(1000); std::vector<std::vector<int>> v; ...
v.resize(v.size()+1, x); 

В случае с пересылкой x копируется один раз к параметру изменения размера. И затем внутренне, так как код может не знаю во время компиляции, насколько изменяется размер вектора, x обычно копируется (не перемещается) во второй раз из параметра изменения размера в соответствующее место внутри вектора.

С помощью ссылки pass-by-const-x в приведенном выше примере необходимо, чтобы копируется только один раз. В этом случае x имеет дорогостоящий конструктор копирования и поэтому любые копии, которые могут быть сохранены, представляют значительную экономию.

Если мы можем быть эффективными для push_back, мы должны быть эффективны для изменить размер. Изменение размера с ссылочным параметром закодирован и отправлены в библиотеку CodeWarrior без сообщений о проблемах о котором я знаю.