2012-03-27 95 views
2

此代码是否适用于所有符合标准的C++编译器(它适用于g ++)?为什么(如果可能,请给出C++ 11参考)?一般来说,std :: unordered_map和关联容器怎么样?关联容器中的end()迭代器

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

std::map<std::string, std::string>::iterator i(map.end()); 

map.insert({"bla", ""}); 
map.insert({"hah", ""}); 

assert(map.end() == i); 

回答

2

对于地图来说,是的 - 实际上只是删除引用的对象会使地图中的迭代器失效。

对于unordered_map,在实践中,对于这个特定的情况可能是这样 - end迭代器通常与其他迭代器有点不同,所以它可能不包含任何实际地址或类似的东西 - 它只是一个特殊的sentinel值在遍历整个容器后,其他迭代器将进行比较。

虽然这并不能保证。具体来说,你的插入可能会导致重新哈希,[编辑:这里我或多或少地假设你的两个插入是作为一个任意数量的插入的占位符。你可以计算出重新哈希是否发生在一个特定的加载因子,插入次数等等,但你通常不希望 - 取决于它导致脆弱的代码]和重新哈希无效迭代器(§23.2.5/ 8)。尽管(如上所述)由end()返回的迭代器通常是“特殊的”,但标准并不要求这样,因此在插入之后,您之前从end获得的内容可能是无效的,因此几乎没有任何要求(包括比较等于特别的任何东西)。

+0

如果标准说“不会影响迭代器的有效性,我会假设包含'end()'返回的迭代器,这是不是真的? – 2012-03-27 09:39:02

+0

是的,'end'返回的是一个迭代器,所以如果你的动作不会使迭代器失效,它将保持有效。 – 2012-03-27 09:42:16

+0

许多很好的答案,但我检查了这一个,因为它最接近我遇到的问题。我使用end()迭代器作为'这是一个无效的迭代器'指示器(种类'NULL'迭代器),这可能导致可避免的错误,因为存储的end()迭代器不能保证等于如果使用无序的关联容器,则它最初来自容器的end()迭代器。 – user1095108 2012-03-27 11:35:45

0

代码使用initialiazer列表扩展看过来:

map.insert({"bla", ""}); // the {"bla", ""} 

这是一个C++ 11的功能,因此将不能在非C++ 11个编译工作。

工作的编译器:

  • GCC 4.4.1和所有更高版本

不工作:

  • 数字火星C++
  • 的Borland C++(不完全是主流,但仍然检查)
  • Visual C++
  • 不支持C++ 11
+0

事实上,我只是要求从C++ 11标准中引用,但无论如何,如果你愿意的话,你可以用C++ 03的方式插入。 end()迭代器是否会在插入时保持不变?看到assert()?如果代码不能编译,你不能检查它是否工作。 – user1095108 2012-03-27 09:22:56

+0

@ user1095108对不起,没有正确理解你的问题,稍等片刻,我会尽量找到一个参考。 – ApprenticeHacker 2012-03-27 09:25:00

1

从C++ 03标准部显然大多数编译23.1.2关联容器[lib.associative.reqmts],点8种状态:

的插入成员不应影响迭代器和对容器的引用的有效性,并且擦除成员应仅使迭代器和对擦除元素的引用无效。

从C++ 11标准部23.2.4关联容器[associative.reqmts],点9的状态:

插入构件不应影响迭代器和引用到的有效性容器,并且擦除 成员应仅使迭代器和对擦除元素的引用无效。

基于此,发布代码中的assert()将为true

编辑:

这些报价是不unordered容器的情况:参见回答Jesse

+0

我在C++ 11标准23.2.4中发现了一个类似的声明:插入和emplace成员不应该影响迭代器和对容器的引用的有效性, ,并且擦除成员只应使迭代器和对已擦除的引用无效元素。谢谢。 – user1095108 2012-03-27 09:34:18

+0

@ user1095108,只是将它添加到我的答案。 – hmjd 2012-03-27 09:35:10

+0

@ user1095108这不适用于unordered_map,请参阅下面的答案。 – juanchopanza 2012-03-27 09:44:18

2

看来你正在寻找从标准关于迭代符无效报价:

对于set, multiset, map and multimap

插入元件不得影响迭代器和引用到容器的有效性,并擦除 成员应仅使迭代器和对擦除元素的引用无效。

对于unordered_set, unordered_map, unordered_multiset, and unordered_multimap

插入构件不应影响迭代器的有效性,如果(N + N)< Z * B,其中N是之前的插入物在所述容器元件的数量 操作,n是插入的元素的数量,B是容器的桶数,z是容器的最大负载因子。

所以,map插入并不会使该end迭代器,为unordered_map它将如果加入元素的现有数量的元件数量超过bucket_count * max_load_factor

0

end迭代器指示不能迭代进一步遍历一个包含,因此当新元素插入到容器中时应该会发生更改。

maps通常作为二叉树实现,并可能使用特殊值(如NULL)来指示进一步的迭代是不可能的。但这是底层实现的结果,与指定的行为无关。