[英]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];
如果索引未事先映射,則會添加一個值初始化元素,這將為標量零初始化,這意味着您將正式開始為零 。
值得一提的是,對於具有隱式聲明的構造函數的任何類型 ,都會發生類似的活動。 無論是否瑣碎,都會發生一些有趣的事情。
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.5Initializers,(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與容器中任何元素的鍵不匹配,則該函數將使用該鍵插入一個新元素,並返回對其映射值的引用。 請注意,即使沒有為元素指定映射值(使用其默認構造函數構造元素),這也會將容器大小增加1。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.