std :: unordered_map运算符[]是否对不存在的密钥进行零初始化?


25

根据cppreference.com,std::map::operator[]对于不存在的值进行零初始化。

但是,同一站点没有提及的零初始化std::unordered_map::operator[],但确实有一个依赖于此的示例。

当然,这只是参考站点,而不是标准站点。那么,下面的代码是否正确?

#include <unordered_map>
int main() {
    std::unordered_map<int, int> map;
    return map[42];     // is this guaranteed to return 0?
}

13
@Ælex,您无法可靠地测试是否已初始化某些内容
idclev 463035818

2
@Ælex我不太了解,您怎么能不初始化std::optional呢?
idclev 463035818

2
@Ælex无法测试对象是否已初始化,因为对未初始化对象的任何操作(初始化除外)都会导致未定义行为。甲std::optional保持无载值对象仍然是初始化的对象。
bolov '19

2
值对象是值初始化的,而不是零初始化的。对于标量类型,它们是相同的,但是对于类类型,它们是不同的。
aschepler '19

@bolov我昨天尝试使用gnu 17和std 17对其进行测试,奇怪的是,我得到的只是零初始化。我以为std::optional has_value可以测试,但是失败了,所以我想您是对的。
Ælex

Answers:


13

取决于我们在说的过载,std::unordered_map::operator[]等效于[unord.map.elem]

T& operator[](const key_type& k)
{
    return try_­emplace(k).first->second;
}

(带有右值引用的重载只是k移入try_emplace,否则是相同的)

如果k映射中键下存在元素,则将try_emplace迭代器返回到该元素和false。否则,try_emplace在key下插入一个新元素k,并向其和true [unord.map.modifiers]返回一个迭代器:

template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);

对我们来说有趣的是,尚无元素[unord.map.modifiers] / 6的情况

否则插入类型的对象value_­type与构造piecewise_­construct, forward_­as_­tuple(k), forward_­as_­tuple(std​::​forward<Args>(args)...)

(带有右值引用的重载只是k移入,forward_­as_­tuple并且在其他方​​面相同)

由于value_typepair<const Key, T> [unord.map.overview] / 2,所以这告诉我们新的map元素将被构造为:

pair<const Key, T>(piecewise_­construct, forward_­as_­tuple(k), forward_­as_­tuple(std​::​forward<Args>(args)...));

由于args来自时为空operator[],因此可以归结为我们的新值,它是pair从不带参数[pairs.pair] / 14的成员构造而成的,该参数是使用以下类型的值的直接初始化[class.base.init] / 7作为初始化器,可以归结为值初始化[dcl.init] /17.4。的值初始化为零初始化[dcl.init] / 8。自然零初始化将其初始化为0 [dcl.init] / 6T()intintint

因此,可以,您的代码保证返回0…


21

在您链接的网站上说:

当使用默认分配器时,这将导致从key复制构造key,并且对映射的值进行值初始化。

所以,int值初始化

值初始化的影响是:

[...]

4)否则,该对象被零初始化

这就是为什么结果是0

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.