【问题标题】:c++ what does "iter = ++iter" do? is it valid?c++ "iter = ++iter" 是做什么的?它有效吗?
【发布时间】:2011-11-08 04:38:43
【问题描述】:

我有一个关于 c++ 标准迭代器的问题。

假设iterstd::set<SomeType>::iterator 类型。

是:

iter = ++iter 

同:

++iter 

或者它们有什么不同?


编辑:

我找到了一个代码std::set<UserDefinedClass*>::iterator 被那样使用。 (指针)
我想知道这是否会导致我正在调试的程序出现故障。
我正在阅读答案,但很难判断哪个答案是正确的。

【问题讨论】:

  • 我认为这是 UB,因为程序格式不正确
  • @iammilind:如果您担心序列点,请记住这些是迭代器,而不是原始类型。所以++是运算符重载,所以这里有一个序列点;因此行为是明确定义的。
  • @iammilind:C++ 术语中的“格式错误”指的是一个包含可诊断错误的程序,即简单地说是一个无法编译的程序。另一方面,UB 通常是不可诊断错误的结果。上例中的iter = ++iter 不是格式错误的。

标签: c++ stl iterator


【解决方案1】:

这个问题没有明确的答案。答案取决于std::set<SomeType>::iterator 类型的性质。如果它是用户定义的类型(即具有重载运算符的类),则定义iter = ++iter 的行为实际上等同于仅仅++iter。然而,如果std::set<SomeType>::iterator 是一个内置类型,那么iter = ++iter 会产生未定义的行为,因为它在一个表达式中修改了同一个对象两次而没有插入序列点(违反语言标准的 5/4 中提出的要求) )。

因此,理论上在一般情况下应该避免做类似的事情,因为在一般情况下行为是未定义的。实际上,std::set<SomeType>::iterator 通常是用户定义的类型,iter = ++iter 可以工作。不过,这不是在代码中使用此类表达式的理由。

【讨论】:

  • 是否可以将std::set<X>::iterator 作为内置函数的类型定义?我最初的反应是不让*iter 工作,那么只有X* 才能工作,但++iter--iter 工作的方式意味着set 必须被实施作为一个数组,但是你不能从set 的中间删除一个元素并保持对其他元素的有效迭代器。我可能错过了一些东西,但我认为这是不可能的。
  • @AndreyT:如果std::set<SomeType>::iterator 是内置类型,那么iter = ++iter 会产生未定义的行为 [citation strongly needed]
  • @Charles Bailey:我不明白如何实现兼容的std::set,同时迭代器可以通过内置实现。这就是为什么我说在现实生活中它应该“工作”。但在一般情况下,我不会放弃这种可能性。
  • @AndreyT:编辑更好,但我仍然想了解为什么分配不引入序列点。世界上怎么可能与其他任何事情同时进行呢?序列点不是精确放置以防止发生并行评估吗?
  • @Mehrdad:我不理解“并行”参考。赋值没有引入序列点,因为标准没有说它引入了序列点。赋值改变其 LHS 的事实是赋值的副作用++ 更改其参数的事实是++副作用。在这种情况下,您有两个相互竞争的副作用(“竞争”= 作用于同一个对象)。语言并不关心这些副作用会导致相同的最终结果。每次你有多个副作用影响同一个对象时,行为是不确定的。
【解决方案2】:

是的,它们是一样的——但为什么要这样做?

【讨论】:

  • 否,前者未定义。同一个变量在同一个序列点内被修改两次。
  • 我正在调试一个代码,这行代码看起来很可疑,想确认它是否是一个有效的代码
  • @ereOn:函数调用operator=的参数求值后的序列点呢?这不是将++= 分开吗?
  • @Charles Bailey:好吧,我可能错了,但我记得 OP 提出了一个非常相似的问题,有人很好地解释了这是如何未定义的。我只是无法得到它。也许是关于i = i++ 而不是i = ++i(不确定它是否会改变某些东西)。这是一个反问还是你确定它有效?
  • @ereOn:是的,可能是i++ 而不是++i
【解决方案3】:

是的,同样的事情。一个更简单的例子,同样的事情:

int i = 10;   //i = 10
int j = i++;  //j = 10
int k = ++i;  //k = 12

然而

i = ++i; 

是不必要的,因为它增加 i 然后将 i 分配给 i

【讨论】:

  • 这不仅没有必要,而且对于 int 来说也是不允许,因为它会在没有中间序列点的情况下两次更改 i 的值。该问题可能使用重载运算符(函数调用),因此结果不同(且已定义)。
  • 不会投反对票,但我同意@Alf。 “通过示例证明”在未定义行为的情况下不起作用——根据定义,U.B.可以包括“合理”的行为。
猜你喜欢
  • 1970-01-01
  • 2021-04-06
  • 2020-10-14
  • 1970-01-01
  • 2021-12-19
相关资源
最近更新 更多