【问题标题】:Is it a good idea to create an STL iterator which is noncopyable?创建一个不可复制的 STL 迭代器是个好主意吗?
【发布时间】:2011-02-03 19:51:47
【问题描述】:

大多数时候,STL 迭代器是 CopyConstructable,因为一些 STL 算法需要这样做来提高性能,例如 std::sort

然而,我一直在做一个宠物项目来包装 FindXFile API (previously asked about),但问题是不可能围绕这个 API 实现可复制的迭代器。查找句柄不能以任何方式复制——DuplicateHandle 明确禁止将这些类型的句柄传递给它。而且,如果您只是维护对查找句柄的引用计数,那么任何副本的单个增量都会导致所有副本的增量 - 显然这不是副本构造的迭代器应该做的事情。

由于我无法满足这里对迭代器的传统复制构造要求,是否值得尝试创建“STL 风格”迭代器?一方面,创建一些其他枚举方法不会落入正常的 STL 约定,但另一方面,如果用户稍后尝试 CopyConstruct 它,遵循 STL 约定会使该迭代器的用户感到困惑。

两害相权取其轻?

【问题讨论】:

  • 学究式地说,如果它不可复制,它就不会成为 STL 迭代器。 :)

标签: c++ winapi stl iterator


【解决方案1】:

不是前向迭代器的输入迭代器是可复制的,但您只能“使用”其中一个副本:增加其中任何一个副本会使其他副本无效(取消引用其中一个不会使其他副本无效)。这允许它被传递给算法,但算法必须通过一次完成。您可以通过检查它们的要求来判断哪些算法是可以的 - 例如,copy 只需要一个 InputIterator,而adjacent_find 需要一个 ForwardIterator(我找到的第一个)。

在我看来,这似乎描述了您的情况。只需复制句柄(或引用句柄的东西),不要复制它。

用户必须明白它只是一个 InputIterator,但实际上这没什么大不了的。 istream_iterator 是一样的,也是出于同样的原因。

鉴于 C++11 的后见之明,要求 InputIterator 可移动但不要求它们可复制几乎是有意义的,因为无论如何重复的使用都是有限的。但那是“有限使用”,而不是“无用”,无论如何,考虑到有多少代码依赖于现有定义,现在从 InputIterator 中删除功能为时已晚。

【讨论】:

  • 我不认为复制输入迭代器 invalidate (不是在标准中那个词的意义上)原始迭代器。它确实有副作用(也就是说,如果在++it2 之前或之后调用*it1 的结果可能会有所不同),但AFAIK 的所有副本都不会失效。标准中的表 72 在 §24.1.1/2 中将 a = u 定义为有效操作,并且后置条件未提及任何无效。§24.1.1/3 处理仅存在于输入迭代器中的特定行为: a == b 不暗示++a == ++b(即仅在单遍算法中有效)
  • 为了保持输入迭代器的语义,必须在复制的迭代器的不同实例之间共享句柄,并且您必须确保在适当的时间释放句柄,而不是更早/更晚。
  • @David:是的。通常我通过使用带有不可复制内部类和boost::shared_ptr 的 pimpl 习惯用法来做到这一点。
  • @dribeas:正确。正如我所说,允许复制输入迭代器。在 24.1.1 中,表 24 说明了 operator++ 的后置条件:“r 的先前值的任何副本不再需要可取消引用或位于 == 的域中”。我认为“无效”是对此的合理总结,尽管它实际上并没有说您不能增加先前值的副本然后取消引用 that。它确实说(1)它不一定给出与你第一次递增的结果相同的结果,并且(2)你“应该”永远不要这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 2021-10-15
  • 2018-06-15
  • 2016-05-29
  • 1970-01-01
相关资源
最近更新 更多