简体   繁体   English

std :: map :: begin()之前的STL迭代器

[英]STL iterator before std::map::begin()

In C++11's std::map , is there some valid iterator x such that ++ x is guaranteed to equal map::begin() ? 在C ++ 11的std::map ,是否有一些有效的迭代器x使得++ x保证等于map::begin() I would like to detect if a function I just called (mine) has walked an iterator off the front of a function. 我想检测一下我刚刚调用的函数(我的)是否已经从函数前面走了一个迭代器。 The function will move the iterator exactly one position backward. 该函数将迭代器向后移动一个位置。

Does the answer hold for the rest of the library? 答案是否适用于图书馆的其他部分?

No, iterators before the beginning in std containers are all UB (except for reverse iterators, which will probably not solve your problem). 不,在std容器中开始之前的迭代器都是UB(反向迭代器除外,这可能无法解决您的问题)。

You probably need to fix the function in question. 您可能需要修复有问题的功能。 Failing that, wrap it and catch the bad behavior before you call it. 如果失败了,请在调用之前将其包装并捕获不良行为。 Failing that, you could insert a negative infinity element into the map key type ordering, and add a sentinal value. 如果不这样做,您可以在map键类型排序中插入负无穷大元素,并添加一个sentinal值。 Failing that, you could write iterator adapters that wrap your map iterators with ones that can go one-before-beginning without UB. 如果做不到这一点,你可以编写迭代器适配器来封装你的map迭代器,它们可以在没有UB的情况下开始。

These are ordered in my order of recommendation, roughly. 这些是按我的推荐顺序排列的。 Each has ways it could fail, and they get more error prone and dangerous as my recommendation gets more remote. 每种方法都有失败的方式,而且随着我的推荐变得更加偏远,它们会更容易出错并且更加危险。

It's very important to realize that Standard Library containers are semi-open ranges [begin, end) , ie you can iterate one-past-the-end. 非常重要的是要意识到标准库容器是半开放范围[begin, end) ,即你可以迭代一次过去。 For bidirectional (and random) iterators you can also do --end() and come back from the brink. 对于双向(和随机)迭代器,您也可以执行--end()并从边缘返回。 Dereferencing one-past-the-end by *end() is undefined behavior, and so is decrementing the begin iterator by --begin() or begin() - 1 . 通过*end() --begin()引用一个*end()是未定义的行为,因此通过--begin()begin() - 1递减开始迭代器。 There is only one exception to this: std::forward_list which has a non-dereferenceable iterator before_begin() that satisfies ++before_begin() == begin() (but note that for a forward_list you cannot decrement begin() either). 这只有一个例外: std::forward_list有一个before_begin()引用的迭代器before_begin() ,它满足++before_begin() == begin() (但请注意,对于forward_list你也不能减少begin() )。

This fundamental asymmetry for bidirectional iterators means that reverse iterators are thin wrappers around regular iterators. 双向迭代器的这种基本不对称性意味着反向迭代器是常规迭代器周围的薄包装器。 In most Standard Library implementations they simply contain a copy base_ of the underyling iterator. 在大多数标准库实现中,它们只包含underyling迭代器的副本base_ Incrementing a std::reverse_iterator calls something like --base_; return *this; 增加std::reverse_iterator调用类似--base_; return *this; --base_; return *this; , and dereferencing it does auto old = base_; return *--old; ,并取消引用它会auto old = base_; return *--old; auto old = base_; return *--old; . At no point is the underlying iterator decremented to before begin() , and no dereferencing of end() is done that way. begin()之前,底层迭代器决不会减少,并且不会以这种方式解除end()解除引用。

Below are the four ways to iterate over a container supporting bidirectional or random iterators, and the relations between the various iterators ( .base() converts a std::reverse_iterator back to its underlying iterator) 下面是迭代支持双向或随机迭代器的容器的四种方法,以及各种迭代器之间的关系( .base()std::reverse_iterator转换回其底层迭代器)

#include <iomanip>
#include <iostream>
#include <iterator>
#include <map>
#include <string>

int main()
{    
    auto c = std::map<int, std::string>{ {1, "hello"}, {2, "world"} };

    {   // 1) forward iteratation
        auto it = begin(c);
        for (; it != end(c); ++it){}
        std::cout << std::boolalpha << (it == c.rbegin().base()) << "\n";
    }

    {   // 2) meh, backward iteration
        auto it = end(c);
        for (; it != begin(c); --it){}
        std::cout << std::boolalpha << (it == c.rend().base()) << "\n";
    }

    {   // 2') better: reverse iteration
        auto it = c.rbegin();
        for (; it != c.rend(); ++it){}
        std::cout << std::boolalpha << (it.base() == begin(c)) << "\n";
    }

    {   // 1') backward reverse, better avoid this
        auto it = c.rend();
        for (; it != c.rbegin(); --it){}
        std::cout << std::boolalpha << (it.base() == end(c)) << "\n";
    }
}

Live Example 实例

If you have data structure that should support bidirectional iteration but there are no member iterators .rbegin() or rend() , you can easily define them yourself by std::reverse_iterator(end()) and std::reverse_iterator(begin()) , respectively (this is also the way the Standard Library usually implements them). 如果你的数据结构应该支持双向迭代但是没有成员迭代器.rbegin()rend() ,你可以通过std::reverse_iterator(end())std::reverse_iterator(begin())自己定义它们。 std::reverse_iterator(begin()) ,分别(这也是标准库通常实现它们的方式)。

By "walk the iterator off the front" I presume you are decrementing a forward iterator something like this: 通过“从前面走迭代器”我假设你正在递减这样的前向迭代器:

// don't do this:
for(it = mymap.end(); --it >= mymap.begin(); ) { ... }

Instead, increment a reverse iterator like this: 相反,增加一个反向迭代器,如下所示:

// this is better:
for(it = mymap.rbegin(); it != mymap.rend(); ++it) { ... }

-Jesse -Jesse

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

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