制作迭代器的副本是一个坏主意吗?

Ste*_*mit 4 c++ iterator

我正在考虑编写一些代码来归结为这一点。 T是一个集合类型(当前std::map,如果重要的话)。

T coll;

// ...

T::iterator it, prev;

prev = coll.end();

for(it = coll.begin(); it != coll.end(); ++it) {
    if(prev != coll.end())
        { do something involving previous element; }

    do something involving this element;

    prev = it;
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,是否在任何方面一个坏主意,复制itprev这个样子?作风不好?可能会惹恼某个地方的学究?可能会根据类型的细微细节而中断T吗?

我不希望coll在此循环运行时被销毁,也不希望在其中添加或删除任何元素。

一方面,我所知道的关于迭代器的一切都表明这应该是非常安全的。但另一方面,我对迭代器有一些不了解,这感觉有点粗略,所以我想我会问。


附录:

出现这种情况的另一个原因是我的实际代码不会涉及for我上面写的循环。我实际上拥有的是事件驱动的代码;看起来更像这样:

void onStartDoingSomething() {
    it = coll.start();
    prev = coll.end();
    startOperation(it, prev);
    timerStart();
}

void onTimer() {
    if(finished with operation on it) {
        prev = it;
        ++it;
        startOperation(it, prev);
        if(it == coll.end() {
            timerStop();
            call operation finished;
        }
    }
}

void startOperation(T::iterator next, T::iterator prev) {
    if(prev != coll.end()) {
        finish operation on prev;
    }

    if(next != coll.end()) {
        start operation on next;
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,另一种表述我的问题的方式可能是,“您是否必须仅在严格的传统循环中使用迭代器、集合类begin()end()方法for,或者您可以任意使用它们?for循环中是否保留了任何状态,或者在迭代器中声明所有内容?” 现在,我知道没有什么比“状态存储在for 循环”,据我所知,迭代器包含它需要的所有状态是最重要的。因此,如果事实上,迭代器不仅包含它需要的所有状态,而且还可以 100% 安全地复制,那么对我最初的问题的回答是“不,这不是一个坏主意”。但是迭代器可能不是 100% 安全可复制的潜在可能性——例如,如果复制迭代器时存在微妙的别名问题,则增加原始值,然后尝试使用副本——这就是为什么这段代码对我来说总是那么粗略。

Mil*_*nek 7

这取决于迭代器的类型,但对于std::map::iterator.

迭代器分为不同的类别,这取决于它们支持的操作以及它们提供的关于它们所引用的值的保证。

std::map::iterator满足BidirectionalIterator概念的要求。这意味着,除其他外,增加迭代器的副本不会使原始副本无效。这意味着这样做prev = it; ++it不会 invalidate prev,所以你的算法是明确定义的。

然而,并非所有迭代器都是这种情况。该InputIterator概念不提供此保证。注意 的后置条件++i

后置条件: 的先前值的任何副本i不再需要可取消引用或位于 的域中==

我不知道标准库中的任何迭代器如果增加它们的副本就会失去它们的价值,但我个人构建了这样一个迭代器类型(它迭代存档文件中的条目,前一个条目是当您前进到下一个时不再可读)。

又见IteratorForwardIteratorRandomAccessIterator,和OutputIterator概念。他们都建立在彼此的基础上。