首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用带有返回shared_ptr的函数的std::map::emplace正确吗?

使用带有返回shared_ptr的函数的std::map::emplace正确吗?
EN

Stack Overflow用户
提问于 2018-10-10 16:27:20
回答 1查看 1.6K关注 0票数 2

如果有返回std::shared_ptr<T>的函数,应该如何在std::map<U, std::shared_ptr<T>>中插入函数调用的结果:使用insertmake_pair,还是只使用emplace

假设我已经知道没有重复的键,而且我是单线程的。

代码语言:javascript
运行
复制
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一起工作吗

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-10-11 18:53:18

我认为这是正确的。

RVO

--我认为,只要在编译器中实现RVO,它就能正常工作,因为bar()返回时态对象,编译器知道从bar()返回什么对象。此外,在C++17和以上的情况下,RVO是受保护的。

RVO (返回值优化)适用于所有对象吗?

什么是复制省略和返回值优化?

emplace vs. . insert (演示)

std::map::emplace

在……里面

代码语言:javascript
运行
复制
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

在……里面

代码语言:javascript
运行
复制
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实现被认为如下所示:

代码语言:javascript
运行
复制
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())中,我希望看到以下内容:

  • ( 1) RVO以std::make_shared<Foo>()代替std::make_shared<Foo>()
  • 2) RVO还将std::make_pair替换为std::pair::pair
  • 3)创建std::shared_prtr<Foo>,然后将其转发给std::pair::pair
  • 4) std::shared_prtr<Foo>是由move-ctor作为一个元素second创建的。

最后,r值也重载了std::map::insert

代码语言:javascript
运行
复制
// since C++11
template< class P >
std::pair<iterator,bool> insert( P&& value );

再来一次

  • 5) move-ctor of std::shared_prtr<Foo> .

总之,我希望

代码语言:javascript
运行
复制
my_map.insert(make_pair("key", bar()));

调用移动电话的std::shared_ptr<Foo> 二次。

我的答案

因为在这两种情况下,根本没有std::shared_ptr<Foo>的副本,并且调用了几乎相同数量的移动ctors,它们的性能几乎是一样的。

将物体移动到地图中

在operator[]地图中插入vs emplace vs c++

c++11 operator[]是否等同于地图插入的位置?

注1 .普遍参考

在C++11和over中,std::make_pair的左参数和右参数都是Scott所称的通用参考,也就是说,它们可以同时接受l值和r值:

代码语言:javascript
运行
复制
// 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,我们得到

代码语言:javascript
运行
复制
template <class... Args>
pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);

如果容器中已经存在键args,则此函数不会构造k。虽然我们已经知道在当前的问题中没有重复的密钥,但是如果我们不知道是否有重复的密钥,这个std::map::try_emplace将是首选的。

在C++1z中嵌入?

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52744844

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档