要插入的值的状态
State of the value to insert
如果insert
returns false
,传递给插入的值是否可能在移动插入后留在moved from状态?
#include <memory>
#include <map>
#include <cassert>
struct less
{
template< typename T >
bool operator () (const std::shared_ptr<T> & lhs, const std::shared_ptr<T> & rhs) const
{
return *lhs < *rhs;
}
};
int main() {
using key_type = int;
using value_type = int;
using map_type = std::map<std::shared_ptr<key_type>, std::shared_ptr<value_type>, less>;
map_type m;
auto p = typename map_type::value_type{std::make_shared<key_type>(1), std::make_shared<value_type>(1)};
if (!m.insert(p).second) {
assert(false);
}
assert(p.first);
assert(p.second);
if (m.insert(std::move(p)).second) {
assert(false);
}
assert(p.first);
assert(p.second);
}
是否定义了最后两个断言实现的行为?
从 [map.modifiers/2] 到 std::map::insert
,我们有
template<class P>
pair<iterator, bool> insert(P&& x);
[...]
Effects: The first form is equivalent to return emplace(std::forward<P>(x))
.
所以它在 std::map::emplace
... 来自 [associative.reqmts/8](强调我的):
a_uniq.emplace(args)
Effects: Inserts a value_type
object t
constructed with std::forward<Args>(args)...
if and only if there is no element in the container with key equivalent to the key of t
.
因此,如果容器中已经有一个与等效键关联的对象,不会进行构造。
让我们用 Llvm 实现中的 <map>
进行验证。在下文中,我删除了部分代码以使其更具可读性。首先,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>
管理的资源。另一个分支 只是让参数保持不变 .
如果insert
returns false
,传递给插入的值是否可能在移动插入后留在moved from状态?
#include <memory>
#include <map>
#include <cassert>
struct less
{
template< typename T >
bool operator () (const std::shared_ptr<T> & lhs, const std::shared_ptr<T> & rhs) const
{
return *lhs < *rhs;
}
};
int main() {
using key_type = int;
using value_type = int;
using map_type = std::map<std::shared_ptr<key_type>, std::shared_ptr<value_type>, less>;
map_type m;
auto p = typename map_type::value_type{std::make_shared<key_type>(1), std::make_shared<value_type>(1)};
if (!m.insert(p).second) {
assert(false);
}
assert(p.first);
assert(p.second);
if (m.insert(std::move(p)).second) {
assert(false);
}
assert(p.first);
assert(p.second);
}
是否定义了最后两个断言实现的行为?
从 [map.modifiers/2] 到 std::map::insert
,我们有
template<class P> pair<iterator, bool> insert(P&& x);
[...]
Effects: The first form is equivalent to
return emplace(std::forward<P>(x))
.
所以它在 std::map::emplace
... 来自 [associative.reqmts/8](强调我的):
a_uniq.emplace(args)
Effects: Inserts a
value_type
objectt
constructed withstd::forward<Args>(args)...
if and only if there is no element in the container with key equivalent to the key oft
.
因此,如果容器中已经有一个与等效键关联的对象,不会进行构造。
让我们用 Llvm 实现中的 <map>
进行验证。在下文中,我删除了部分代码以使其更具可读性。首先,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>
管理的资源。另一个分支 只是让参数保持不变 .