emplace, 安放
C++11 大部分stl容器新提供的一个新的插入方式,根据容器的特性,可能有
emplace
emplace_back
emplace_front
区别于已有的insert push等,emplace可避免不必要的中间临时对象产生,提升性能。
参考std::set的emplace说明:
template <class... Args> pair<iterator,bool> emplace (Args&&... args);
Construct and insert element
Inserts a new element in the set, if unique. This new element is constructed in place using args as the arguments for its construction.
The insertion only takes place if no other element in the container is equivalent to the one being emplaced (elements in a set container are unique).
If inserted, this effectively increases the container size by one.
Internally, set containers keep all their elements sorted following the criterion specified by its comparison object. The element is always inserted in its respective position following this ordering.
The element is constructed in-place by calling allocator_traits::construct with args forwarded.
A similar member function exists, insert, which either copies or moves existing objects into the container.
1. 插入时就地构造.
2. 插入后容器size相应增加
例:
class CItem
{
public:
CItem(int n):m_Id(n){
std::cout<<"construct "<< m_Id << std::endl;
}
bool operator< (const CItem &a) const
{
return a.m_Id<m_Id;
}
CItem(const CItem& a){
m_Id = a.m_Id;
std::cout<<"copy construct "<< m_Id << std::endl;
}
int m_Id;
};
int main()
{
std::set<CItem> set_tmp;
set_tmp.insert(CItem(1));
set_tmp.insert(CItem(2));
set_tmp.insert(CItem(2));
set_tmp.emplace(3);
set_tmp.emplace(3);
return 0;
}
construct 1
copy construct 1
construct 2
copy construct 2
construct 2
construct 3
construct 3
可以看到原来的insert会多一次拷贝构造,emplace则不会
附上set的源码:
先__construct_node构造一个对象,指针放入__h, 一个unique_ptr (__node_holder)中,如果没找到,则把指针insert,__inserted=true,unique_ptr释放指针,如果找到了,则不插入,内存由unique_ptr析构时处理。
template <class _Tp, class _Compare, class _Allocator>
template <class... _Args>
pair<typename __tree<_Tp, _Compare, _Allocator>::iterator, bool>
__tree<_Tp, _Compare, _Allocator>::__emplace_unique_impl(_Args&&... __args)
{
__node_holder __h = __construct_node(_VSTD::forward<_Args>(__args)...);
__parent_pointer __parent;
__node_base_pointer& __child = __find_equal(__parent, __h->__value_);
__node_pointer __r = static_cast<__node_pointer>(__child);
bool __inserted = false;
if (__child == nullptr)
{
__insert_node_at(__parent, __child, static_cast<__node_base_pointer>(__h.get()));
__r = __h.release();
__inserted = true;
}
return pair<iterator, bool>(iterator(__r), __inserted);
}