Ответ 1
Для того, как это может показаться непонятным (читайте ниже), учитывая текущее состояние спецификации, вы не можете сделать какое-либо предположение о состоянии аргумента после возврата вызова функции.
Чтобы понять, почему, прежде всего, укажите, что функция члена insert()
определена в терминах emplace()
(см. 23.4.4.4/1):
Первая форма эквивалентна
return emplace(std::forward<P>(x))
. [...]
Пост-условия emplace()
в свою очередь указаны как (см. п. 23.2.4, Таблица 102):
Вставляет
value_type
объектt
, построенный сstd::forward<Args>(args)...
если и только если нет элемент в контейнере с ключ, эквивалентный ключуt
. Компонентbool
возвращаемая параtrue
, если и только если вставка место и итератор компонент парных точек к элементу с ключом эквивалентно ключуt
.
Предложение, выделенное жирным шрифтом из приведенной выше цитаты (акцент мой), говорит о том, что пара, которая станет элементом карты, если ключ еще не присутствует, будет построен по ходу непосредственно из пары rvalue, которую вы поставляете.
Это сделало бы очень разумным вывод о том, что реализациям сначала нужно будет проверить, присутствует ли ключ, и только если нет, переместите-построить новый элемент карты из вашей пары.
Однако "очень разумный" не является веским аргументом при рассмотрении спецификации формального языка. В этом случае, с формальной точки зрения, ничего не мешает реализации выполнить следующее:
- Сначала переместите - постройте пару
tmp
из вашего аргумента (что означало бы, что вы не можете делать предположения о состоянии вашего аргумента после возвращения функции); - Проверьте, присутствует ли ключ на карте;
- Если нет, выполните необходимые операции, чтобы вставить
tmp
в контейнер.
Или даже:
- Проверьте, присутствует ли ключ на карте;
- Если это так, вставьте новый элемент, перемещенный из вашего аргумента,
- Если нет, переместите-конструируйте новый объект из своего аргумента и ничего не сделайте с ним.
Пункт 3 выше абсолютно бессмыслен, но формально он не запрещен. Запомните формулировку:
Вставляет a
value_type
объектt
, построенный сstd::forward<Args>(args)...
если и только если нет элемент в контейнере с ключ, эквивалентный ключуt
.
Это говорит только о том, что если в контейнере нет элемента с ключом, эквивалентным ключу t
, в карту не будет вставлен объект, построенный из t
, но, насколько глупо это может звучать, он не говорит, что никакой объект вообще не должен быть перемещен из t
: если он не вставлен в карту, это разрешено.
Это говорит о том, что, поскольку Стандарт явно не ограничивает реализацию в этом отношении, вы не можете делать предположения о том, был ли перенесен ваш аргумент. Следовательно, вы не можете делать предположения о состоянии, в котором будет находиться ваша пара, когда возвращается вызов функции (в соответствии с пунктом 17.6.5.15).
Если я могу позволить личным мнением проникнуть, хотя, я считаю, что это недостаток.