关于c ++:迭代通过std :: map的顺序是否已知(并且由标准保证)?

Is the order of iterating through std::map known (and guaranteed by the standard)?

我的意思是,我们知道std::map的元素是根据键排序的。那么,假设键是整数。如果我使用forstd::map::begin()迭代到std::map::end()的话,标准是否保证我将按升序遍历带有键的元素?

例子:

1
2
3
4
5
6
7
8
9
10
std::map<int, int> map_;
map_[1] = 2;
map_[2] = 3;
map_[3] = 4;
for( std::map<int, int>::iterator iter = map_.begin();
     iter != map_.end();
     ++iter )
{
    std::cout << iter->second;
}

是否保证打印234或定义了它的实现?

现实生活中的原因:我有一个带int键的std::map。在非常罕见的情况下,我想用键遍历所有元素,它大于具体的int值。是的,听起来std::vector是更好的选择,但请注意我的"非常罕见的情况"。

编辑:我知道,std::map的元素是经过排序的。无需指出(这里的大多数答案)。我甚至把它写在我的问题里。当我遍历一个容器时,我询问了迭代器和顺序。感谢@kerrek sb的回答。


是的,那是有保证的。此外,*begin()给出了由比较运算符确定的最小元素和*rbegin()最大元素,并且认为表达式!compare(a,b) && !compare(b,a)为真的两个关键值ab相等。默认比较函数为std::less

排序不是幸运的额外功能,而是数据结构的一个基本方面,因为排序用于确定两个键何时相同(根据上述规则),并执行有效的查找(本质上是一个二进制搜索,在元素数量上具有对数复杂性)。


这是由C++标准中的关联容器要求保证的。例如,在C++ 11中看到23.2.4/10:

1
2
3
4
5
6
The fundamental property of iterators of associative containers is that they
iterate through the containers in the non-descending order of keys where
non-descending is defined by the comparison that was used to construct them.
For any two dereferenceable iterators i and j such that distance from i to j is
positive,
  value_comp(*j, *i) == false

和23.2.4/11

1
2
For associative containers with unique keys the stronger condition holds,
  value_comp(*i, *j) != false.


我认为数据结构中存在混乱。

在大多数语言中,map只是一个关联容器:它将一个键映射到一个值。在"更新的"语言中,这通常是使用哈希图实现的,因此不保证顺序。

然而,在C++中,情况并非如此:

  • std::map是已排序的关联容器
  • EDCOX1(15)是在C++ 11中引入的基于哈希表的关联容器。

所以,为了澄清订货时的保证。

在C++ 03中:

  • std::setstd::multisetstd::mapstd::multimap保证按钥匙(及提供的标准)订购。
  • std::multisetstd::multimap中,本标准不对等价元素(即比较相等的元素)施加任何订单保证。

在C++ 11中:

  • std::setstd::multisetstd::mapstd::multimap保证按钥匙(及提供的标准)订购。
  • std::multisetstd::multimap中,标准规定等价元素(比较相等的元素)按插入顺序排列(首先插入)
  • 顾名思义,std::unordered_*集装箱没有订购。最值得注意的是,当修改容器时(插入/删除时),元素的顺序可能会改变。

当标准规定元素按某种方式排列时,意味着:

  • 迭代时,可以看到元素的定义顺序
  • 反向迭代时,可以看到元素的顺序相反。

我希望这能消除任何混乱。


Is this guaranteed to print 234 or it's implementation defined?

是的,std::map是一个分类容器,由Key与提供的Comparator一起订购。所以这是有保证的。

I'd like go iterate through all elements, with key, greater than a concrete int value.

这当然是可能的。


对。。。std::map中的元素具有严格的弱顺序,这意味着元素将由一个集合组成(即"相等"的键不会重复),并且通过对任意两个键a和b进行测试来确定相等性,如果键a不小于键b,b不小于a,则键a等于键b。

也就是说,如果该类型的弱排序不明确(在您的情况下,使用整数作为键类型,这不是问题),则无法对std::map的元素进行正确排序。您必须能够定义一个操作,该操作在您的std::map中的键所使用的类型上定义一个总顺序,否则您将只能对元素或poset有一个部分顺序,它具有a可能无法与b比较的属性。在这种情况下,通常会发生的情况是,您可以插入键/值对,但如果在整个映射中迭代,则可能以重复的键/值对结束,并且/或在尝试对映射中的特定键/值对执行std::map::find()时检测到"丢失"的键/值对。


begin()可以给出最小的元素。但这取决于实施情况。它是在C++标准中指定的吗?如果没有,那么做出这种假设是危险的。