С [map.modifiers / 2] на std::map::insert
, у нас есть
template<class P>
pair<iterator, bool> insert(P&& x);
[...]
Эффекты: первая форма эквивалентна return emplace(std::forward<P>(x))
.
Так что это в std::map::emplace
... из [associative.reqmts / 8] (выделено мной):
a_uniq.emplace(args)
Эффекты: Вставляет value_type
объект t
, созданный с std::forward<Args>(args)...
, тогда и только тогда, когда в контейнере нет элемента с ключом, эквивалентным ключу t
.
Следовательно, конструкция не имеет место, если в контейнере уже есть объект, связанный с эквивалентным ключом.
Давайте проверим с <map>
из реализации Llvm. Далее я удалил некоторые части кода, чтобы сделать его более читабельным. Сначала std::map::insert
делает это:
template <class _Pp, /* some SFINAE... */>
/* symbol visibility ... */
pair<iterator, bool> insert(_Pp&& __p)
{return __tree_.__insert_unique(_VSTD::forward<_Pp>(__p));}
Давайте перейдем к __tree::insert_unique
, затем:
pair<iterator, bool> __insert_unique(__container_value_type&& __v) {
return __emplace_unique_key_args(_NodeTypes::__get_key(__v), _VSTD::move(__v));
}
Все еще не там ... но в __tree::emplace_unique_key_args
приходит:
/* Template, template, template... return value... template */
__tree</* ... */>::__emplace_unique_key_args(_Key const& __k, _Args& __args)
{
__parent_pointer __parent;
__node_base_pointer& __child = __find_equal(__parent, __k);
__node_pointer __r = static_cast<__node_pointer>(__child);
bool __inserted = false;
if (__child == nullptr)
{
/* Some legacy dispatch for C++03... */
// THIS IS IT:
__node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
__inserted = true;
}
return pair<iterator, bool>(iterator(__r), __inserted);
}
Я думаю, нам не нужно заглядывать в __find_equal(__parent, __k)
, чтобы понять, что __child == nullptr
- это условие, которое запускает фактическую вставку. В этой ветке вызов __construct_node
переадресует аргументы, которые украдут ресурсы, которыми управляет передаваемый вами std::shared_ptr<int>
. Другая ветка просто оставит аргументы нетронутыми .