使用+=运算符可以安全地使用[]创建新的std::map条目
Safe to use += operator to create a new std::map entry using []?
假设我有一个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;
}
在调用operator[]
时,由于先前未映射的键而插入到映射中的元素是初始化的值。如果您没有见过该语法,请考虑()
在以下代码片段中的特殊含义。parens很重要。它们在初始化树中引入了与默认初始化不同的跳闸。两者都很重要;两者都是按照语言标准制定的。
int i = int();
事实证明,标量(包括指针)的值初始化最终屈服于零初始化。虽然看起来很奇怪,但前面的代码段值初始化int
的一个实例,由于int
是标量,该实例变为零初始化,然后将其复制到i
。(公平地说,几乎肯定会有一些淘汰,但基本面是这样的)。
无论如何,由于该功能,当您这样做时,您可以放心:
m_map[0] += 1;
甚至这个:
++m_map[0];
如果索引之前没有映射,则会添加一个值初始化的元素,这将为标量进行零初始化,这意味着您将正式从zero开始。
值得一提的是,对于具有隐式声明构造函数的任何类型,都会发生类似的活动。不管琐碎与否,都会发生一些有趣的事情。
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
)。但是,在我们的容器中映射到0
的a
成员是否仍然可靠地初始化为零(因此,在上行之后的1
)是的是。
如果对引用的不同初始化路径感到好奇,请参阅此问答。或者查看C++11标准,特别是C++11§8.5初始化程序(p5、p7、p10)。值得一读。
即使使用较短的代码段,也可以保证获得1。
关键是operator[]
必须在返回对它的引用之前在映射中创建元素,所以当你到达+=
时,元素已经存在,如果现在必须创建,则值为零(因为映射的元素是值初始化的)。
(顺便说一句,这就是为什么当您使用以类类型为值的std::map
时,如果您想使用operator[]
,即使您立即为其分配对象,它也必须具有默认构造函数的原因)
是的,这很好,新条目默认为值value_type()
,即int
的0
。
它仍然做+=
,但0 += 1
给出1
。
Map使用默认构造函数进行延迟初始化。(所有int为零)
因此,如果映射中不存在0
,则会将其初始化为包含值0,并在+= 1
之后添加1。
因此,您可以毫无顾虑地使用更高版本的代码。
引用从cplusplus.com 调用map_obj[k]的效果
如果k与容器中某个元素的键匹配,则函数返回对其映射值的引用。
如果k与容器中任何元素的键都不匹配,则函数插入带有该键的新元素并返回引用到其映射值。请注意,这总是会增加容器即使没有为元素分配映射值(元素是使用其默认构造函数构造的)。
- 使用std::multimap迭代器创建std::list
- ";结果类型必须是可从输入范围的值类型""构造的;创建std::vector时
- C++如何创建 std::map
- 在共享缓冲区内存中创建 ::std::string 对象
- 创建 std::string 的二维数组的最佳做法
- 从 T 创建 std::future 的最佳方式<T>
- 是否可以从 std::any 创建 std::any 与 std::reference_wrapper?
- 从编译时已知的日历日期创建"std::chrono::time_point"
- 创建 std::函数,它返回具有函数成员值的变量.分段错误
- 如何从可变参数模板参数创建 std::tuple<>?
- 使用成员函数创建std::函数不会编译
- 通过预处理器创建 std::p air<std::string,some_enum>
- 创建 std::set 只复制一个元素,如何解决这个问题?
- 动态创建 std::vector 并将其传递给另一个函数的各种方法
- 编译问题 C++ 同时,尝试通过调用另一个对象中的成员函数来创建 std:: 线程
- 从函数应用程序创建 std::vector
- 创建 std::thread 时出现错误 C2280,未在 C++ 中初始化
- 使用std :: to_string()创建std :: String时的segfault
- 将C 数组写成文件,避免创建std :: String
- 稍后使用<Class>调用类构造函数创建 std::vector