递减 std::vector::begin 是不是未定义,即使从未使用过?
Posted
技术标签:
【中文标题】递减 std::vector::begin 是不是未定义,即使从未使用过?【英文标题】:Is decrementing std::vector::begin undefined, even if it is never used?递减 std::vector::begin 是否未定义,即使从未使用过? 【发布时间】:2019-11-25 22:10:15 【问题描述】:请注意,与关于该主题的许多问题相反(可能是为什么我在 google 和 *** 上都找不到这个问题的令人满意的答案),我从不取消引用 *(begin() - 1)
我的要求是:
向后迭代 使用不带反向迭代器的函数,在本例中为vector::erase()
尽量保持代码干净,所以尽量避免以下心理杂耍:
vector.erase(rev_it.base() - 1)
(反向迭代器现在应该是什么来获取迭代中的下一个元素?erase()
返回的迭代器?+ 1
,可能?- 1
,不太可能?)
我想出的是:
for (auto it = vector.end(); it-- != vector.begin(); )
if (condition(*it))
it = vector.erase(it);
这似乎可行,因为it--
返回迭代器的值,而 then 只会递减它,这意味着迭代器总是在 在检查之后但 在之前递减进入循环体。
特别是:
进入循环时
如果vector.end() == vector.begin()
向量为空,我们立即退出循环
如果vector.end() != vector.begin()
然后我们进入循环,第一个循环体执行it == vector.end() - 1
擦除元素时
vector.erase(it)
返回向量中的以下元素,因此在每次迭代时递减迭代器让我们只考虑向量中的每个元素。
退出循环时
在最后一次执行循环体时,it == vector.begin()
,所以下一次我们尝试循环条件:
false
it
最后一次减一
我们退出循环
也就是说,我的代码确实计算迭代器位置begin() - 1
,但从不访问它,也不使用它进行比较或类似的东西。
这是未定义的行为吗?
我会冒段错误或其他风险吗?或者只是访问未初始化的数据?什么都没有,因为迭代器在被使用之前就被丢弃了?没有办法知道吗?
【问题讨论】:
因遗漏未定义。无论如何,为什么不使用反向迭代器? “意味着迭代器总是在检查之后但在进入循环体之前递减” - 这根本不是真的。迭代器被复制到一个临时,然后递减,然后临时副本按值返回。这是可以实现迭代器类上的后减运算符的唯一(也是正确的)方式。迭代器在检查前处于 UB 土地;只是不是迭代器开始参与检查;副本是。 @WhozCraig 它只是出现那样,实际情况并非如此,你说的完全正确。让我编辑它。这不会改变我的问题的底线:这个递减的未定义迭代器重要吗? 最终你的问题是,在序列开始时(即 begin())对双向迭代器应用减量操作是否合法。据我所知,唯一支持它的容器迭代器是std::forward_list
,它支持before_begin()
迭代器的构造。顺便说一句,你不是第一个问这个问题的人。 See here。建议与此处相同:反向迭代器。
@WhozCraig 实际上我可能已经将球门柱移动了一点,我会恢复它。你的第一条评论是我正在寻找的或真正的。即使我似乎不依赖它当前的行为,也愿意用一两个词来说明为什么 UB 不好?
【参考方案1】:
怎么样
for (auto it = vector.end(); it != vector.begin(); )
--it;
... rest of the loop body
【讨论】:
以上是关于递减 std::vector::begin 是不是未定义,即使从未使用过?的主要内容,如果未能解决你的问题,请参考以下文章
Javascript中的递增/递减运算符是不是被认为是错误的形式? [复制]
C ++迭代器取消引用和前缀递增/递减样式? *--Iter ok 风格是不是明智?