Ответ 1
Хотя std::move
на самом деле не выполняет никакого перемещения, а также std::make_pair
, std::make_pair
пересылает свои аргументы в конструктор std::pair
, который инициализирует два своих члена из этих аргументов.
Таким образом, ход выполняется в этой точке, прежде чем std::map
имеет шанс что-либо сделать. Итак, да, вы закончили "сломанный" ход по уважительной причине.
Вы должны уметь использовать emplace
(чтобы пропустить конструкцию пары). Из таблицы 102:
Эффекты: Вставляет объект
T
T
, построенный с помощьюstd::forward<Args>(args)...
, если и только если в контейнере нет элемента с ключом, эквивалентным ключуT
.
Очевидно, что библиотека по-прежнему "переадресовывает" в этот момент, поэтому предварительно перемещается, и в вашем случае emplace не будет иметь место, поэтому все выражение должно быть эффективным no-op.
Однако, libstdС++ из У GCC 4.8.0, похоже, есть ошибка в этом отношении: emplace
вызывает _M_emplace_unique
на внутреннем дереве, который пересылает аргументы to _M_create_node
, который переводит аргументы allocator_traits<_Node_allocator>::construct
, который пересылает аргументы _S_construct
, который переводит аргументы в __a.construct
, который с помощью распределителя по умолчанию равен std::allocator<std::pair<const _Key, _Tp> >::construct
, который является конструктором пары, который вы пытались избежать... все перед проверкой столкновения в _M_emplace_unique
.
Можно утверждать, что стандарт неоднозначен в этом отношении, но я бы назвал это нарушением намерений. Опять же, clang v3.4 с libС++ тоже демонстрирует это поведение, равно как и Visual Studio 2012. Так что, если моя стандартная интерпретация верна, это не работает все три основных инструментальных цепочки.
Я думаю, они все решили, что "если и только если" применяется к вставке, а не к вставке и конструкции.
Я разместил вопрос о std-discussion, чтобы спровоцировать улучшение перехода из таблицы 102, чтобы авторитетно ответить на этот вопрос раз и навсегда.