【问题标题】:Subtracting 1 vs decrementing an iterator减 1 与递减迭代器
【发布时间】:2021-11-25 07:15:03
【问题描述】:

the accepted answer to "Iterator to last element of std::vector using end()--"@barry 声明:

请注意,如果 vector::iterator 只是 T*(这将是有效的),则上面的第一种形式是非良构的。后两者不管用,所以更可取。

参考他的代码:

std::vector<int>::iterator it = --container.end();
std::vector<int>::iterator it = container.end() - 1;
std::vector<int>::iterator it = std::prev(container.end());

这一观点在 cmets 中存在争议,但没有明确的解决方案。所以这就是我的问题:第一个和第二个之间的语义差异到底是什么?对于 vector 以外的结构的迭代器,答案是否会有所不同?

【问题讨论】:

  • Mark Ransom 的最后一条评论 “右值是临时值...” 似乎在这里回答了这个问题。您对该评论有任何疑问或困惑吗?
  • 所以答案是确实,第一行会导致未定义的行为?当迭代器类型(任何容器的)是不重载-- 运算符的类型时会发生这种情况?如果是这样,我会接受这个效果的答案。
  • 据我了解,对于std::vector,所有 3 种可能性都可以。我没有看到--container.end() 的问题。 end() 返回一个迭代器,-- 递减它。作为一般规则,任何对原始指针有效的语法也应该对std::vector 有效。
  • @Phil1970 std::vector 可以为其迭代器类型使用原始指针,在这种情况下,-- 将不起作用。
  • @ByteEater 如果迭代器不可逆,则尝试使用 -- 将无法编译。

标签: c++ pointers iterator undefined-behavior pointer-arithmetic


【解决方案1】:

对于任何标准库容器,成员函数end() 返回一个右值。在您将其分配给变量之前,它是“临时的”。

减量运算符-- 不需要在右值迭代器上工作。您将修改一个临时的,C++ 历史上已采取措施避免。

因此,--container.end() 可能会在符合标准的 C++ 编译器上编译。但它可能不会。

std::prev(container.end()) 将适用于每个符合标准的编译器。


审核:

  • --container.end() 可能无法编译。这取决于实施。
  • container.end() - 1 只会在容器使用随机访问迭代器时编译。
  • std::prev(container.end()) 将始终编译。

如果它们编译,所有三种形式都会产生相同的结果。

【讨论】:

  • 它提供了很多相关信息,谢谢。您显然对此很了解,所以请您让您的答案完全适合我的问题并添加这些缺失的部分:
  • --container.end()是什么错误?编译时错误(如果是这样,是关于错误的类型,为什么可能——标准没有明确地规定这些?)?未定义的行为?还有什么?
  • container.end() - 1 是否总是等同于 std::prev(container.end())?如果不是(我想你可以为你自己的容器类型定义一个迭代器类型,它重载 --- 并具有你实现的任何语义),它是否保证适用于标准库容器?
  • (此评论是在您第一次编辑后添加的。)您写道:“因此,--container.end() 可能会在您的符合标准的 C++ 编译器上编译。但它可能不会。”所以,如果我理解正确,标准说end 应该返回一个迭代器,但将确切的类型保留为实现定义的?如果是,是否要求--container.end()编译后,其语义相同?
  • (此评论是在您的第二次编辑后添加的。)是否还要求如果使用随机访问迭代器(我想,vector 是强制性的,但对于其他一些容器),container.end() - 1 具有相同的语义?
猜你喜欢
  • 2021-11-21
  • 2012-08-16
  • 1970-01-01
  • 2021-02-09
  • 1970-01-01
  • 1970-01-01
  • 2021-04-10
  • 2023-03-31
  • 1970-01-01
相关资源
最近更新 更多