繁体   English   中英

迭代 std::map 的顺序是否已知(并由标准保证)?

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

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


例子:

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() ,它是由比较运算符确定的最大元素,以及两个键值ab ,表达式为!compare(a,b) && !compare(b,a)是真的被认为是平等的。 默认比较函数是std::less<K>

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

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

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

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

我认为数据结构存在混淆。

在大多数语言中, map只是一个AssociativeContainer:它将一个键映射到一个值。 在“较新”的语言中,这通常使用哈希映射来实现,因此不保证订单。

但是,在C ++中,情况并非如此:

  • std::map是一个已排序的关联容器
  • std::unordered_map是C ++ 11中引入的基于哈希表的关联容器

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

在C ++ 03中:

  • 保证根据键(和提供的标准)对std::setstd::multisetstd::mapstd::multimap进行排序
  • std::multisetstd::multimap ,标准不对等效元素强加任何顺序保证(即那些比较相等的元素)

在C ++ 11中:

  • 保证根据键(和提供的标准)对std::setstd::multisetstd::mapstd::multimap进行排序
  • std::multisetstd::multimap ,标准规定等效元素(比较相等的元素)按照它们的插入顺序排序(首先插入)
  • std::unordered_*容器,顾名思义,未订购。 最值得注意的是,当容器被修改时(插入/删除时),元素的顺序可能会改变。

当标准说元素以某种方式排序时,它意味着:

  • 迭代时,您会看到定义顺序的元素
  • 当反向迭代时,您会看到相反顺序的元素

我希望这可以解决任何困惑。

这是保证打印234还是它的实现定义?

是的, std::map是一个已排序的容器,由Key和提供的Comparator排序。 所以它是有保证的。

我想用密钥迭代所有元素,大于具体的int值。

这肯定是可能的。

是的...... std::map的元素具有严格的弱排序,这意味着元素将由一个集合组成(即,不会重复“等于”的键),并确定相等性通过测试任意两个密钥A和B,如果密钥A不小于密钥B,并且B不小于A,则密钥A等于密钥B.

话虽如此,如果该类型的弱排序不明确(在您的情况下,您使用整数作为键类型,这不是问题),您无法正确排序std::map的元素。 您必须能够定义一个操作,该操作定义您在std::map中使用的类型的总顺序,否则您将只有元素的部分顺序,或者poset,它具有A可能的属性在这种情况下通常会发生的事情是,您将能够插入键/值对,但如果您遍历整个地图,则可能最终会出现重复的键/值对,和/或当您尝试在std::map::find()执行特定键/值对的std::map::find() ,检测“缺少”键/值对。

为了完整起见,我想提一下,如果您的容器包含指针,则由于ASLR 的原因,每个新程序运行的迭代顺序可能会有所不同。 因此,即使一次运行的顺序确定性的,但多次运行中的顺序不是

这对于正确性是否重要取决于特定程序。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM