【问题标题】:Safe to use += operator to create a new std::map entry using []?使用 += 运算符是否可以安全地使用 [] 创建新的 std::map 条目?
【发布时间】:2014-06-13 12:53:59
【问题描述】:

假设我有一个std::map<int, int>,这样做安全吗?

std::map<int, int> m_map;
m_map[0] += 1;

如果我这样做时映射中不存在键 0,它如何知道将 1 添加到什么值?

我希望 std::map 通过执行 = 而不是 += 在值在映射中创建新条目的情况下处理此问题。这将使我不必这样做:

std::map<int, int>::iterator it = m_map.find(0);
if(it != m_map.end()) {
    it->second += 1;
}
else {
    m_map[0] = 1;
}

【问题讨论】:

标签: c++ map


【解决方案1】:

由于先前未映射的键而在调用 operator[] 时插入到映射中的元素是值初始化。如果您还没有看到该语法,请考虑 () 在以下代码 sn-p 中的特殊含义。括号很重要。它们在初始化树中引入了不同于 default-initialization 的旅程。两者都很重要;两者都由语言标准规定。

int i = int();

事实证明,标量(包括指针)的值初始化最终会屈服于零初始化。虽然看起来很奇怪,但之前的 sn-p 值初始化了一个 int 的实例,由于 int 是一个标量,它变成了零初始化,然后将其复制到 i。 (公平地说,几乎可以肯定会有一些省略,但基本面如前所述)。

无论如何,由于该功能,您可以放心:

m_map[0] += 1;

甚至这个:

++m_map[0];

如果之前未映射索引,则会添加一个值初始化元素,该元素将对标量进行零初始化,这意味着您将正式从 开始。

值得一提的是,对于具有隐式声明的构造函数的任何类型,都会发生类似的活动。不管是不是微不足道的事情,都会发生一些有趣的事情。

struct S { int a; int b; };
std::map<int, S> mymap;

++mymap[0].a;

上述执行后,a 成员是否可靠地映射到我们容器中的0 1是的,是的。此外,考虑一下:

struct S { int a; std::string str; };
std::map<int, S> mymap;

++mymap[0].a;

现在S 有一个重要的隐式构造函数(它必须,因为它必须构造str)。但是a 成员是否映射到我们容器中的0仍然可靠地进行零初始化(因此1 在上述行之后)? 是的,是的。

如果对引用的不同初始化路径感到好奇,see this question and answer。或者查看 C++11 标准,特别是 C++11 § 8.5 Initializers, (p5,p7,p10)。值得一读。

【讨论】:

    【解决方案2】:

    保证即使使用较短的 sn-p,您也会得到 1。

    关键是operator[] 必须在地图中创建元素之前返回对它的引用,所以当你到达+= 时,该元素已经存在,并且,如果现在必须创建它,值为零(因为地图的元素是值初始化的)。

    (顺便说一句,这就是为什么当你使用带有类类型作为值的std::map时,如果你想使用operator[],它必须有一个默认构造函数,即使你给它分配了一个对象立即)

    【讨论】:

      【解决方案3】:

      是的,这很好,新条目默认值为value_type(),即0 对应int

      它仍然是+=,但0 += 11

      【讨论】:

        【解决方案4】:

        Map 使用默认构造函数进行延迟初始化。(所有 int 为零)

        所以它@98​​7654322@在map中不存在,它会被初始化为包含值0并且在+= 1之后添加1。

        这样你就可以放心使用高版本的代码了。

        引用cplusplus.com调用map_obj[k]的效果

        如果 k 匹配容器中某个元素的键,则函数 返回对其映射值的引用。

        如果 k 不匹配容器中任何元素的键,则 函数使用该键插入一个新元素并返回一个引用 到它的映射值。请注意,这总是会增加容器 大小加一,即使没有为元素分配映射值( 元素是使用其默认构造函数构造的)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-07-15
          • 2014-06-06
          • 1970-01-01
          • 2023-03-26
          • 1970-01-01
          • 2021-02-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多