【问题标题】:Is regular overwrite copy mode undefined for Container iterators?容器迭代器是否未定义常规覆盖复制模式?
【发布时间】:2012-09-18 11:17:24
【问题描述】:

下面的代码编译得很好,用v1中的值覆盖v2中的值:

std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = {6, 7, 8, 9, 10};

std::copy(v1.begin(), v1.end(), v2.begin());

std::copy 的第三个参数是一个 OutputIterator。但是,Container 要求指定 a.begin(),其中 a 是一个 Container 对象,其返回类型应为 iterator,其定义为:

任何满足前向迭代器要求的迭代器类别。

前向迭代器要求不包括输出迭代器的要求,那么上面的例子是未定义的吗?我将迭代器用作输出迭代器,即使没有明显的保证它会是一个。

我相当肯定上面的代码是有效的,但是,我猜你可以从容器的细节中推断出begin() 返回的前向迭代器实际上也支持输出迭代器的要求。在那种情况下,begin() not 什么时候返回输出迭代器?只有当容器是const还是有其他情况?

【问题讨论】:

  • a.begin() a 这里是什么?您在示例中使用了 v1v2
  • @NicolBolas 已编辑以清除该问题。谢谢。

标签: c++ c++11 iterator containers


【解决方案1】:

如果前向迭代器是可变的,则它们可以符合输出迭代器的规范,具体取决于序列的类型。它没有明确说明(不像他们输入迭代器需求的事实),但是如果我们看一下需求表

我们可以检查给定的前向迭代器是否符合它们:

*r = o
(§24.2.5/1): 如果X 是可变迭代器,reference 是对T 的引用

可变引用是可赋值的(除非你有一个不可赋值的类型,显然)。

++r, r++, *r++ = o
(§24.2.5 Table 109)

表 109 中的第一行与输出迭代器的要求相同,只是前向迭代器没有备注。第二行比输出迭代器更严格,因为它指定必须返回 reference

底线,如果你有一个可变的前向迭代器到一系列可复制分配的类型,你就有一个有效的输出迭代器

(从技术上讲,具有operator=(...) const 和可变成员的类型序列的常量迭代器也符合条件,但我们希望没有人会这样做。)

【讨论】:

  • 你总结得真棒。谢谢。
【解决方案2】:

前向迭代器要求不包括输出迭代器的要求

这听起来倒退了。 OutputIterators 需要满足比 ForwardIterators 更少 的标准。 (前向迭代器在递增后应该是可重用的,即递增两次应该会产生相同的结果)。

因此,可以提供输出迭代器保持有效直到算法完成。爱荷华州:

auto outit = std::begin(v2);
std::advance(outit, v1.size()); // or: std::distance(std::begin(v1), std::end(v2))
// outit should still be valid here

编辑到评论:

§ 24.2.1

进一步满足输出迭代器要求的迭代器称为mutableiterators。不可变的迭代器被称为constantiterators

现在,让我找到将这两者联系在一起的一点,即 vector::begin() 返回可变随机访问迭代器。

了解详情

§ 24.2.5 前向迭代器 [forward.iterators]

1 类或指针类型 X 满足前向迭代器的要求,如果

  • X 满足输入迭代器 (24.2.3) 的要求,
  • X 满足 DefaultConstructible 要求 (17.6.3.1),
  • 如果 X 是可变迭代器,则引用是对 T 的引用;如果 X 是 const 迭代器,则 reference 是对 const T 的引用,
  • 表 109 中的表达式是有效的并具有指示的语义,并且
  • X 类对象提供多次通过保证,如下所述。

【讨论】:

  • 但是输出迭代器需要 *r = o 有效,而前向迭代器则不需要。前向迭代器满足输入迭代器的要求,但不一定满足输出迭代器的要求。
  • 嗯。我记得我以前见过这种混乱。让我看看能不能找回它的来源
  • 我目前怀疑任何取消引用非 const 类型的前向迭代器也会自动成为输出迭代器,因为 *r = o 确实可以工作。它只是分配给*r 返回的引用。不过,所有这些要求都让我感到困惑。
  • 哇,两个非常棒的答案。我将选择另一个答案,因为它的“底线”。它使答案非常清楚。谢谢!
猜你喜欢
  • 2021-06-09
  • 2021-01-27
  • 2014-06-08
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 2021-09-15
相关资源
最近更新 更多