简体   繁体   English

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

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

What I mean is - we know that the std::map 's elements are sorted according to the keys.我的意思是 - 我们知道std::map的元素是根据键排序的。 So, let's say the keys are integers.所以,假设键是整数。 If I iterate from std::map::begin() to std::map::end() using a for , does the standard guarantee that I'll iterate consequently through the elements with keys, sorted in ascending order?如果我使用forstd::map::begin()迭代到std::map::end() ,标准是否保证我将因此迭代带有键的元素,按升序排序?


Example:例子:

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;
}

Is this guaranteed to print 234 or is it implementation defined?这是保证打印234还是实现定义?


Real life reason: I have a std::map with int keys.现实生活中的原因:我有一个带有int键的std::map In very rare situations, I'd like to iterate through all elements, with key, greater than a concrete int value.在极少数情况下,我想使用大于具体int值的键遍历所有元素。 Yep, it sounds like std::vector would be the better choice, but notice my "very rare situations".是的,听起来std::vector是更好的选择,但请注意我的“非常罕见的情况”。


EDIT : I know, that the elements of std::map are sorted.. no need to point it out (for most of the answers here).编辑:我知道, std::map的元素已排序..无需指出(对于此处的大多数答案)。 I even wrote it in my question.我什至在我的问题中写了它。
I was asking about the iterators and the order when I'm iterating through a container.我在遍历容器时询问了迭代器和顺序。 Thanks @Kerrek SB for the answer.感谢@Kerrek SB 的回答。

Yes, that's guaranteed. 是的,这是有保证的。 Moreover, *begin() gives you the smallest and *rbegin() the largest element, as determined by the comparison operator, and two key values a and b for which the expression !compare(a,b) && !compare(b,a) is true are considered equal. 此外, *begin()为您提供最小的*rbegin() ,它是由比较运算符确定的最大元素,以及两个键值ab ,表达式为!compare(a,b) && !compare(b,a)是真的被认为是平等的。 The default comparison function is std::less<K> . 默认比较函数是std::less<K>

The ordering is not a lucky bonus feature, but rather, it is a fundamental aspect of the data structure, as the ordering is used to determine when two keys are the same (by the above rule) and to perform efficient lookup (essentially a binary search, which has logarithmic complexity in the number of elements). 排序不是幸运的奖励功能,而是它是数据结构的一个基本方面,因为排序用于确定两个键何时相同(通过上述规则)并执行有效查找(实质上是二进制)搜索,其元素数量具有对数复杂度)。

This is guaranteed by Associative container requirements in the C++ standard. 这是由C ++标准中的关联容器要求保证的。 Eg see 23.2.4/10 in C++11: 例如,参见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

and 23.2.4/11 和23.2.4 / 11

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

I think there is a confusion in data structures. 我认为数据结构存在混淆。

In most languages, a map is simply an AssociativeContainer: it maps a key to a value. 在大多数语言中, map只是一个AssociativeContainer:它将一个键映射到一个值。 In the "newer" languages, this is generally achieved using a hash map, thus no order is guaranted. 在“较新”的语言中,这通常使用哈希映射来实现,因此不保证订单。

In C++, however, this is not so: 但是,在C ++中,情况并非如此:

  • std::map is a sorted associative container std::map是一个已排序的关联容器
  • std::unordered_map is a hash-table based associative container introduced in C++11 std::unordered_map是C ++ 11中引入的基于哈希表的关联容器

So, in order to clarify the guarantees on ordering. 所以,为了澄清订购的保证。

In C++03: 在C ++ 03中:

  • std::set , std::multiset , std::map and std::multimap are guaranteed to be ordered according to the keys (and the criterion supplied) 保证根据键(和提供的标准)对std::setstd::multisetstd::mapstd::multimap进行排序
  • in std::multiset and std::multimap , the standard does not impose any order guarantee on equivalent elements (ie, those which compare equal) std::multisetstd::multimap ,标准不对等效元素强加任何顺序保证(即那些比较相等的元素)

In C++11: 在C ++ 11中:

  • std::set , std::multiset , std::map and std::multimap are guaranteed to be ordered according to the keys (and the criterion supplied) 保证根据键(和提供的标准)对std::setstd::multisetstd::mapstd::multimap进行排序
  • in std::multiset and std::multimap , the Standard imposes that equivalent elements (those which compare equal) are ordered according to their insertion order (first inserted first) std::multisetstd::multimap ,标准规定等效元素(比较相等的元素)按照它们的插入顺序排序(首先插入)
  • std::unordered_* containers are, as the name imply, not ordered. std::unordered_*容器,顾名思义,未订购。 Most notably, the order of elements may change when the container is modified (upon insertion/deletion). 最值得注意的是,当容器被修改时(插入/删除时),元素的顺序可能会改变。

When the Standard says that elements are ordered in a way, it means that: 当标准说元素以某种方式排序时,它意味着:

  • when iterating, you see the elements in the order defined 迭代时,您会看到定义顺序的元素
  • when iterating in reverse, you see the elements in the opposite order 当反向迭代时,您会看到相反顺序的元素

I hope this clears up any confusion. 我希望这可以解决任何困惑。

Is this guaranteed to print 234 or it's implementation defined? 这是保证打印234还是它的实现定义?

Yes, std::map is a sorted container, ordered by the Key with the supplied Comparator . 是的, std::map是一个已排序的容器,由Key和提供的Comparator排序。 So it is guaranteed. 所以它是有保证的。

I'd like go iterate through all elements, with key, greater than a concrete int value. 我想用密钥迭代所有元素,大于具体的int值。

That is surely possible. 这肯定是可能的。

Yes ... the elements in a std::map have a strict weak-ordering, meaning that the elements will be composed of a set (ie, there will be no repeats of keys that are "equal"), and equality is determined by testing on any two keys A and B, that if key A is not less than key B, and B is not less than A, then key A is equal to key B. 是的...... std::map的元素具有严格的弱排序,这意味着元素将由一个集合组成(即,不会重复“等于”的键),并确定相等性通过测试任意两个密钥A和B,如果密钥A不小于密钥B,并且B不小于A,则密钥A等于密钥B.

That being said, you cannot properly sort the elements of a std::map if the weak-ordering for that type is ambiguous (in your case, where you are using integers as the key-type, that is not a problem). 话虽如此,如果该类型的弱排序不明确(在您的情况下,您使用整数作为键类型,这不是问题),您无法正确排序std::map的元素。 You must be able to define a operation that defines a total order on the type you are using for the keys in your std::map , otherwise you will only have a partial order for your elements, or poset, which has property where A may not be comparable to B. What will typically happen in this scenario is that you'll be able to insert the key/value pairs, but you may end up with duplicate key/value pairs if you iterate through the entire map, and/or detect "missing" key/value pairs when you attempt to perform a std::map::find() of a specific key/value pair in the map. 您必须能够定义一个操作,该操作定义您在std::map中使用的类型的总顺序,否则您将只有元素的部分顺序,或者poset,它具有A可能的属性在这种情况下通常会发生的事情是,您将能够插入键/值对,但如果您遍历整个地图,则可能最终会出现重复的键/值对,和/或当您尝试在std::map::find()执行特定键/值对的std::map::find() ,检测“缺少”键/值对。

For completeness sake I'd like to mention that if your container includes pointers , the iteration order may differ in each new program run due to ASLR .为了完整起见,我想提一下,如果您的容器包含指针,则由于ASLR 的原因,每个新程序运行的迭代顺序可能会有所不同。 So even though the order in one run is deterministic, the order across multiple runs is not .因此,即使一次运行的顺序确定性的,但多次运行中的顺序不是

Whether this is important for correctness depends on particular program.这对于正确性是否重要取决于特定程序。

begin() may give the smallest element. begin()可以给出最小的元素。 But it is implementation depended. 但这是实施所依赖的。 Is it specified in the C++ standard? 它是在C ++标准中指定的吗? If not, then it is dangerous to make this assumption. 如果没有,那么做出这个假设是危险的。

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

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