【问题标题】:How to insert / emplace into map to avoid creation of temporary objects?如何在地图中插入/放置以避免创建临时对象?
【发布时间】:2015-01-21 14:33:33
【问题描述】:

我正在阅读 C++11 书籍之一的建议,在将项目添加到容器时更喜欢 emplace 而不是 insert,以避免创建临时对象(调用对象的构造函数/析构函数)插入)。但我有点困惑,因为有几种可能性可以将对象添加到地图,例如

#include <iostream>
#include <string>
#include <cstdint>
#include <map>

int main()
{
    std::string one     { "one" };
    std::string two     { "two" };

    std::map<uint32_t, std::string> testMap;

    testMap.insert(std::make_pair(1, one));         // 1
    testMap.emplace(2, two);                        // 2
    testMap.insert(std::make_pair(3, "three"));     // 3
    testMap.emplace(4, "four");                     // 4

    using valType = std::map < uint32_t, std::string >::value_type;
    testMap.emplace(valType(5, "five"));            // 5
    testMap.insert(valType(6, "six"));              // 6

    return 0;
}

还有一些底层机制在阅读这样的代码时不会立即可见 - 完美转发、隐式转换......

向地图容器添加项目的最佳方式是什么?

【问题讨论】:

    标签: c++11 insert perfect-forwarding emplace


    【解决方案1】:

    让我们一次考虑一个选项(加上你没有提到的一两个选项)。

    就语义而言,选项 1 和 6 基本相同。 usingpair 只是map 的value_type 的两种不同拼写方式。如果您愿意,可以使用typedef 而不是using 语句添加第三​​种方式:

    typedef std::map<uint32_t, std::string>::value_type valType;
    

    ...并拥有与您的 #6 相当的 C++98/03。不过,这三个最终都做了同样的事情:创建一个 pair 类型的临时对象,并将其插入到 map 中。

    第 3 版和第 5 版的功能几乎相同。他们使用emplace,但他们传递的已经是map 的value_type 的对象。当emplace 本身开始执行时,将存储在映射中的对象类型已经构建好了。同样,两者之间的唯一区别在于用于指定 pair 类型的语法 - 并且,再次使用上面显示的 typedef,您可以拥有一个 C++98/03 等价于当前具有using 声明的那个。事实上,版本 3 使用 insert 而版本 5 使用 emplace 几乎没有真正的区别——在调用任一成员函数时,我们已经创建并传递了一个临时对象。

    选项 2 和 4 实际上都使用 emplace 更像是它可能的预期 - 传递单个组件,将它们完美转发给构造函数,并就地构造一个 value_type 对象,因此我们避免创建任何临时任何时候的对象。它们两者之间的主要(唯一?)区别在于我们为 value_type 的 string 组件传递的东西是字符串文字(需要从中创建临时 std::string 对象)还是 @987654341 @ 提前创建的对象。

    这两者之间的选择可能很重要。如果(如上所述)你只做一次,它根本不会有任何区别——不管 when 你创建它,你正在创建一个字符串对象,然后把它进入map

    因此,要产生真正的不同,我们需要预先创建字符串对象,然后将相同的字符串对象重复插入map。这本身就很不寻常——在大多数情况下,您将执行一些操作,例如将外部数据读入字符串,然后将其插入map。如果您确实重复插入(由 std::string 构造)相同的字符串文字,那么任何合理的编译器都很有可能检测到生成的字符串是循环不变的,并将 string 构造提升到循环之外,效果基本相同。

    底线:就map 本身的使用而言,选择2 和4 是等价的。在这两者之间,我不会真正努力使用选项 2 而不是选项 4(即预先创建字符串),但它很可能在大多数情况下发生,仅仅是因为将单个字符串文字插入到地图中是很少有用。您放入映射中的字符串将更频繁地来自某些外部数据源,因此您将拥有一个string,因为这是(例如)std::getline 在您从文件中读取数据时给您的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多