Перегрузка std:: unordered_map:: insert
Не могли бы вы научить меня, почему оба
std::unordered_map::insert(const value_type&)
и
template<class P> std::unordered_map::insert(P&&)
существуют в стандарте?
Я думаю, что insert(P&&)
может служить insert(const value_type&)
.
Ответы
Ответ 1
Обе эти перегрузки
auto std::unordered_map::insert(const value_type&) -> ...
template<class P>
auto std::unordered_map::insert(P&&) -> ...
имеют свои преимущества, и ни одна из них не может полностью заменить другую. Первый из них кажется частным случаем второго, так как P
может быть выведено как const value_type&
. Хорошая вещь о второй перегрузке заключается в том, что вы можете избежать ненужных копий. Например, в этом случае:
mymap.insert(make_pair(7,"seven"));
Здесь результат make_pair на самом деле равен pair<int, const char*>
, тогда как value_type
может быть pair<const int, string>
. Таким образом, вместо создания временного объекта value_type
и копирования его в контейнер у нас есть возможность прямого создания объекта value_type
в карте путем преобразования аргумента и/или перемещения его элементов.
С другой стороны, было бы неплохо, если бы это сработало:
mymap.insert({7,"seven"});
Но этот список на самом деле не является выражением! Из-за этого компилятор не может вывести P для второй перегрузки. Первая перегрузка по-прежнему жизнеспособна, так как вы можете скопировать-инициализировать параметр pair<const int,string>
с таким списком.
Ответ 2
Универсальная эталонная перегрузка шаблона была добавлена в n1858 с обоснованием (для map
, но то же самое явно относится к multimap
):
Две из подписей insert
новы. Они были добавлены, чтобы позволить перемещаться из типов r, отличных от value_type
, которые можно конвертировать в value_type
. Когда P
создает экземпляр как lvalue, аргумент копируется в map
, иначе он перемещается в map
(допускают атрибуты констант).
(Другая подпись insert
, на которую ссылается, - insert-with-hint.)
Мы также ссылаемся на обоснование для deque
(опять же, явно ссылающееся на другие контейнеры):
Все функции-члены, которые вставляют (или добавляют, добавляют и т.д.) один объект value_type в контейнер, перегружаются с помощью функции-члена, которая принимает этот value_type по ссылке rvalue, так что единственный объект value_type может быть перемещен в контейнер. Это не только значительно повышает эффективность работы с тяжелыми весами, но и позволяет вставлять в контейнер подвижные, но не скопируемые типы.
Очевидно, что изменения рассматривались главным образом как дополнения; в то время не считалось, что перегрузка шаблона может полностью заменить исходный (С++ 03) insert
. Это можно увидеть, обратившись к предыдущему n1771, который обеспечивает некоторую мотивацию для перегрузки шаблона, используя другой подход:
Обратите внимание на то, что для карты и мультимапа есть две новые перегрузки вставки, причем они берут пару с неконстантным ключом. Нельзя переходить из const key_type и, следовательно, чтобы иметь возможность перемещать key_type на карту (multi), необходимо использовать пару. Существуют перегрузки как пары const lvalue, так и пары non-const rvalue, так что пара lvalue не будет перемещена из.
pair<iterator, bool> insert(const value_type& x); // CC
pair<iterator, bool> insert(const pair<key_type,mapped_type>& x); // CC
pair<iterator, bool> insert(pair<key_type,mapped_type>&& x);
(CC
является аббревиатурой для CopyConstructible
.)
Затем появляется, что перегрузки template
были добавлены к map
и multimap
, не осознавая, что они сделали избыточные перегрузки const value_type &
избыточными. Вы можете рассмотреть возможность отправки отчета о дефектах, чтобы удалить избыточные перегрузки.
Ответ 3
разница заключается в типе используемой ссылки. Первый
std::unordered_map::insert(const value_type&)
использует ссылку Reference (С++ 03), которая теперь называется ссылкой lvalue в (С++ 11). Это должно быть const. С++ 11 представил rvalue Ссылки P&&
, которые не должны быть const.
Для обеспечения обеих функций предусмотрены две функции вставки.
Пожалуйста, ознакомьтесь с этим отличным ответом на StackOverflow wrt rvalue Ссылки в С++ 11, надеюсь, это поможет ответить на ваш вопрос.
Что делает T && (double ampersand) означает в С++ 11?
Как вы сказали, можно использовать rvalue-overload и просто передать константу lvalue ref, но - см. этот текст из http://msdn.microsoft.com/en-us/library/dd293668.aspx
Перегружая функцию для получения ссылки на константу lvalue или ссылки на rvalue, вы можете написать код, который отличает немодифицируемые объекты (lvalues) и изменяемые временные значения (rvalues).
-Hannes