当前位置: 首页 > 知识库问答 >
问题:

复制一个迭代器是个坏主意吗?

谢昂雄
2023-03-14

我正在考虑写一些代码,可以归结为以下几点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;
}

我的问题是,像这样把it复制到prev是不是一个坏主意?糟糕的风格?可能会惹恼某个学究?根据类型T的细微细节是否可能中断?

我不希望coll在这个循环运行时被破坏,也不希望任何元素被添加或删除。

一方面,我对迭代器的了解表明,这应该是完全安全的。但另一方面,我对迭代器有些不了解,这感觉有点粗略,所以我想问一下。

增编:

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

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

所以陈述我的问题的另一种方式可能是,“你必须使用迭代器和集合类的start()end()方法,只在循环的严格传统的中使用,还是可以任意使用它们?是否有任何状态保留在for循环中,或者状态都在迭代器中?"现在,我知道没有什么比“状态存储在for循环中”更好的了,据我所知,迭代器包含它需要的所有状态是至关重要的。所以如果,事实上,迭代器不仅包含了它需要的所有状态,而且100%安全可复制,那么我最初问题的答案是“不,这不是一个坏主意”。但是潜在的可能性迭代器可能不是100%安全的可复制的--例如,如果你复制一个迭代器,增加原始的,然后尝试使用复制,会有微妙的混淆现象--这就是为什么这段代码对我来说总是有点粗略...


共有2个答案

楚博雅
2023-03-14

虽然这并不清楚,但我通常不鼓励存储迭代器。

首先,迭代器的概念旨在抽象您正在访问的内容。这可以是蒸汽或容器。Steam迭代器肯定是不稳定的,存储它们不会产生有效的代码。但是,只要容器不变,将迭代器存储到容器中是安全的。

这是第二个问题,如果您正在访问一个容器,并且只从中读取,那么您的代码就可以了。如果代码在调用之间更改容器,则迭代器可能会失效。当迭代器失效时,不同的容器具有不同的语义,但我的经验法则是,一旦容器调整大小,所有迭代器都无效。

(我不倾向于记住确切的语义,因为我编程时假设我可以随时更改容器,并且向量使调整大小上的所有迭代器无效。)

令狐昂雄
2023-03-14

这取决于迭代器的类型,但对于std::map::iterator,它是合适的。

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

d::映射::迭代器满足了BiDirectionalIterator概念的要求。这意味着,除其他外,递增迭代器的副本不会使原始副本无效。这意味着执行prev=it; it不会使prev无效,因此您的算法定义良好。

然而,并非所有迭代器都是这样。inputierator概念不提供这种保证。注意i的后置条件:

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

我不知道标准库中的任何迭代器会失去它们的值,如果你递增它们的副本,但是我个人已经构建了这样一个迭代器类型(它迭代归档文件中的条目,并且当你前进到下一个)。

另请参阅IteratorForwardIteratorR随机访问IteratorOutputIterator概念。它们都建立在彼此的基础上。

 类似资料:
  • 问题内容: 我需要遍历for循环的每次迭代的值集,但仅对于第一次迭代,它可以正常工作。此后返回。 我很清楚这种行为。 一种解决方案是在for循环中调用方法,因此对于每个for循环迭代,都会对其进行初始化。但这是非常无效的方法,因为它是独立的。 我尝试了此方法,但由于它仅包含参考,因此也无法正常工作。 有什么方法可以将迭代器复制到另一个或其他更好的方法中? 问题答案: An 是可能的最小API,可以

  • 问题内容: 为什么Catch(Exception)一个坏主意? 问题答案: 因为当你捕获异常时,你应该正确处理它。而且,你不能期望在代码中处理所有类型的异常。同样,当你捕获所有异常时,你可能会得到一个无法处理的异常,并阻止堆栈中位于较高位置的代码正确处理它。 一般原则是捕获可能的最特定类型。

  • 问题内容: 似乎我在某处听到/读到了a的内部禁忌。并不是说它不起作用,只是基于它们的显示类型,关于它们的兼容性不佳。找不到任何证据来支持我的预感,所以我可能完全错了。 问题答案: 使用实例a 并不比使用表进行布局的任何其他方式差。(尽管有些人从不使用表格进行布局,而我恰好是其中之一。) 如果您使用的,你会得到但在一种情况,它可能是很难预测的因素将如何调整大小。div的默认值是从其父对象确定其宽度,

  • 问题内容: 有人告诉我不要在JavaScript中使用数组。为什么不? 问题答案: 原因是一种构造: 有时可能与另一个完全不同: 还请注意,JavaScript库可能会执行以下操作,这会影响您创建的任何数组:

  • 问题内容: 许多人告诉我,在控制器中操作DOM是一件非常糟糕的事情,但这究竟是什么原因。它如何影响您正在制作的应用程序?有哪些最佳实践,以及如何实现? 问题答案: 从技术上讲,控制器应该更小,更紧凑,并且不应使用DOM。控制器仅希望具有在事件上被调用的业务逻辑和绑定级别逻辑。 根据我的观点,“ 您不应该从控制器中操作DOM ”背后的原因是,这仅仅是因为关注点分离。如果您从控制器执行DOM操作,那么

  • 本文向大家介绍为什么在JavaScript数组迭代中使用“ for…in”循环是个坏主意?,包括了为什么在JavaScript数组迭代中使用“ for…in”循环是个坏主意?的使用技巧和注意事项,需要的朋友参考一下 在大多数情况下,通常最好使用' for '循环而不是“ for ... in ”循环,因为“ for ... in ”循环会产生索引 ,而不会打扰剩余的索引普通的“ for ”循环显示