如果有返回std::shared_ptr<T>
的函数,应该如何在std::map<U, std::shared_ptr<T>>
中插入函数调用的结果:使用insert
和make_pair
,还是只使用emplace
假设我已经知道没有重复的键,而且我是单线程的。
std::shared_ptr<Foo> bar() {
return std::make_shared<Foo>();
}
std::map<std::string, std::shared_ptr<Foo>> my_map;
// Which makes more sense?
my_map.emplace("key", bar());
// or
my_map.insert(make_pair("key", bar()));
RVO与std::map::emplace
一起工作吗
发布于 2018-10-11 18:53:18
我认为这是正确的。
RVO
--我认为,只要在编译器中实现RVO,它就能正常工作,因为bar()
返回时态对象,编译器知道从bar()
返回什么对象。此外,在C++17和以上的情况下,RVO是受保护的。
emplace vs. . insert (演示)
std::map::emplace
在……里面
my_map.emplace("key", bar());
,RVO将bar()
替换为std::make_shared<Foo>()
,并创建std::shared_ptr<Foo>
。然后它被转发,move-ctor of std::shared_ptr<Foo>
被称为,仅在新元素my_map
的就地构造时就被称为。
std::map::插入std::make_pair
在……里面
my_map.insert(make_pair("key", bar()));
,RVO再次将bar()
替换为std::make_shared<Foo>()
。
接下来,从N3337的20.3.2开始,纠正了小错误的C++11,std::pair
的类模板是
名称空间std{ template结构对{ty对联T1 first_type;second_type;T1第一;T2第二;template对(U& x,V& y);.}
模板ctor在哪里
template对(U& x,V& y); 效果:构造函数用
std::forward<U>(x)
初始化first
,用std::forward<V>(y)
初始化second
。
此外,从20.3.3
template pair make_pair(T1& x,T2& y); 返回:
pair<V1, V2>(std::forward<T1>(x), std::forward<T2>(y))
;
因此,该定义的典型std::make_pair
实现被认为如下所示:
namespace std{
template<class T1, class T2>
inline pair<typename decay<T1>::type, typename decay<T2>::type>
make_pair(T1&& x, T2&& y)
{
return pair<typename decay<T1>::type,
typename decay<T2>::type>
(std::forward<T1>(x), std::forward<T2>(y));
}
}
RVO将再次为std::make_pair
工作。事实上,如果我们用演示和编译器选项"-fno-elide-constructors“编译g++的RVO,那么移动-ctor调用的数量只会增加一个。
因此,在std::make_pair("key", bar())
中,我希望看到以下内容:
std::make_shared<Foo>()
代替std::make_shared<Foo>()
,std::make_pair
替换为std::pair::pair
,std::shared_prtr<Foo>
,然后将其转发给std::pair::pair
,std::shared_prtr<Foo>
是由move-ctor作为一个元素second
创建的。最后,r值也重载了std::map::insert
:
// since C++11
template< class P >
std::pair<iterator,bool> insert( P&& value );
再来一次
std::shared_prtr<Foo>
.总之,我希望
my_map.insert(make_pair("key", bar()));
调用移动电话的std::shared_ptr<Foo>
二次。
我的答案
因为在这两种情况下,根本没有std::shared_ptr<Foo>
的副本,并且调用了几乎相同数量的移动ctors,它们的性能几乎是一样的。
在operator[]地图中插入vs emplace vs c++
注1 .普遍参考
在C++11和over中,std::make_pair
的左参数和右参数都是Scott所称的通用参考,也就是说,它们可以同时接受l值和r值:
// until C++11
template< class T1, class T2 >
std::pair<T1,T2> make_pair( T1 t, T2 u );
// since C++11
template< class T1, class T2 >
std::pair<V1,V2> make_pair( T1&& t, T2&& u );
因此,如果将l-值传递给std::make_pair
,则调用std::shared_ptr<Foo>
的复制-ctor作为通用引用的结果。
注2,std::map::try_emplace
即使键已经存在,std::map::emplace
也总是构造my_map
的新元素。如果密钥已经存在,则销毁这些新实例。但是自从C++17,我们得到
template <class... Args>
pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
如果容器中已经存在键args
,则此函数不会构造k
。虽然我们已经知道在当前的问题中没有重复的密钥,但是如果我们不知道是否有重复的密钥,这个std::map::try_emplace
将是首选的。
https://stackoverflow.com/questions/52744844
复制相似问题