【问题标题】:Define Custom (STL-compatible) Iterator where Value Type is not CopyConstuctible or Assignable定义自定义(与 STL 兼容的)迭代器,其中值类型不是 CopyConstuctible 或 Assignable
【发布时间】:2011-05-04 11:58:50
【问题描述】:

我希望定义一个自定义迭代器,它使用无法复制的值类型。

这样做的基本原理是迭代器将负责 Windows 下的模块枚举,并且我使用 CreateToolhelp32Snapshot/Module32First/Module32Next API 来避免必须预处理整个模块列表(例如,每个迭代器增量应该提前到按需列表中的下一个模块,以避免不必要的开销。)。问题在于这些 API 需要使用由 Toolhelp API 管理的“句柄”,因此除了调用 First/Next 之外,我无法控制列表中的“位置”。

我可以在技术上允许复制句柄,但是你会遇到这样的问题:

auto Iter1 = ModList.begin(); // Assume 'ModList' is an instance of my class which manages construction etc of my iterator
auto Iter2 = Iter1; // Both iterators now point to the first module in the list
++Iter1; // BOTH iterators now point to the second module in this list!! We just 'broke' the expected behavior of 'Iter2'.

是否可以定义一个与 STL 兼容的迭代器(可以与标准算法等一起使用),它可以很好地处理无法复制或分配的值类型?

我还可以在迭代器的实现中将值类型包装在共享指针中,这将使迭代器本身可复制和可分配,但它仍然不能解决上面代码中概述的问题。

注意:如果有帮助,我可以使值类型可移动。

我的代码库中已经严重依赖 Boost,因此请随意建议使用 Boost 的解决方案。

很抱歉这个问题写得不好,我已经有一段时间了,我的大脑不想再正常工作了。 :P 让我知道是否需要澄清。

【问题讨论】:

  • 听起来你真正想要的是生成器函子,而不是迭代器。

标签: c++ windows boost stl iterator


【解决方案1】:

如果您将迭代器标记为 InputIterator 而不是 ForwardIterator,那么您描述的行为并非出乎意料。增加 InputIterator 会使它的副本无效,因此之后它们看起来指向什么并不重要。

您可以将它与接受 InputIterator 的标准算法一起使用,这正是那些可以合理地实现为单通道而不是多通道算法的算法。

但是,根据您的算法实现是否检查迭代器标签,您可能无法获得任何帮助来确保您不会错误地使用它。 InputIterator 和 ForwardIterator 接口的“签名”没有区别,只是在语义上,所以单独的编译时鸭子类型没有帮助。

【讨论】:

  • 啊,那我觉得应该很完美了。我现在觉得很傻。
  • 那么如果增加这样一个迭代器的副本会使其他迭代器无效,那么为什么还要允许副本呢?
  • @SasQ:因为否则(在 C++03 中,当指定迭代器要求时)将无法按值传递和返回迭代器。如果迭代器在 C++11 中是新的,那么只要求 InputIterators 是可移动的、不可复制的并且使可复制成为 ForwardIterator 的要求可能是有意义的。
【解决方案2】:

迭代器在逻辑上应该引用一个元素——它不应该一个元素。您将需要一个模块的后端集合,以及引用此集合中各个元素的迭代器——就像 stdlib 迭代器一样。增加一个迭代器应该使它改变它所引用的实际元素,而不修改后端集合。

对于您的特定问题,您可以创建一个集合,按需继续工具帮助迭代,每当有人引用您尚未迭代的模块时,您在集合中填写更多数据。

【讨论】:

  • 我意识到这一点,但是我试图这样做是为了避免不必要的性能损失。如果用户在说两个模块之后找到了他们想要的东西,我只希望他们为这两个模块付费。不适用于预处理整个列表。
  • @RaptorFactor:按需,或制作输入迭代器(如果适合您的使用)
  • 实际上,我想如果我让后端按需遍历列表,然后缓存结果,并让迭代器存储状态,说明他们引用的列表中的哪个元素可能有效...我不确定,但我必须再考虑一下。这听起来更合理吗?
  • 输入迭代器没问题,但我在示例代码中列出的问题不是还有吗?
  • @RaptorFactor:没有接受 InputIterator 的标准算法会做你描述的事情(获取迭代器的副本并期望它在原始增加后仍然引用引用)。所以没有问题。执行您描述的事情的算法将被标记为至少需要一个 ForwardIterator。 InputIterator 接口设计用于迭代无缓冲、不可搜索的流。就像您的情况一样,这种迭代器类型无法“记住”过去的位置。
猜你喜欢
  • 2021-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
相关资源
最近更新 更多