c++ - 转换视图的 std::prev 上的未定义行为
问题描述
考虑下面的代码(点击这里查看godbolt):
#include <algorithm>
#include <ranges>
#include <vector>
int main() {
auto v = std::vector<short>{1, 2};
auto view = v | std::views::transform([] (auto i) { return static_cast<int>(i); });
auto it = view.begin() + 1;
auto prev_it = std::ranges::prev(it); //this one is fine
//auto prev_it = std::prev(it); //this one dies with an infinite loop
return *prev_it;
}
主要问题:调用std::prev
而不是std::ranges::prev
迭代器会使 gcc 陷入无限循环。这意味着存在编译器错误或代码调用std::prev
调用了未定义的行为——它是哪一个?
关于后者的一些想法:std::prev
需要LegacyBidirectionalIterator,而std::ranges::prev
需要概念bidirectional_iterator 。据我了解,这两者之间的唯一区别是(取自 bidirectional_iterator 的描述):
与LegacyBidirectionalIterator要求不同, bidirectional_iterator概念不需要取消引用来返回左值。
如果这确实意味着调用会std::prev
调用未定义的行为:基本上所有非范围算法在使用新类型的迭代器调用时都会调用未定义的行为,因为LegacyForwardIterator和forward_iterator共享相同的区别?旧算法的约束是否可以不放松到新的迭代器类型,以避免这种情况,因为这仍然是向后兼容的?
解决方案
这意味着存在编译器错误或代码调用
std::prev
调用了未定义的行为——它是哪一个?
后者,尽管 libstdc++ 应该能够检测到此故障并更好地诊断它,就像您要求它一样。
这里的问题是:
auto view = v | std::views::transform([] (auto i) { return static_cast<int>(i); });
view
的迭代器是 C++20 的随机访问迭代器,但是因为它们的引用类型是 prvalue int
,所以它们只能是 C++17 的输入迭代器。这正是 C++20 之前的迭代器模型的工作方式:前向迭代器需要一个真正的引用。
std::ranges::prev
使用 C++20 迭代器类别,std::prev
使用 C++17(或真正的 C++98)迭代器类别。并std::prev
要求BidirectionalIterator
. 未指定库需要在多大程度上尝试验证迭代器确实是双向的,但prev(it, n)
指定为advance(it, -n); return it;
andadvance(it, n)
对于非双向迭代器只会循环直到它命中n
......这对于否定n
显然永远不会发生。
也就是说,如果你使用 Ranges,你应该使用std::ranges::meow
而不是std::meow
在所有情况下,因为这个迭代器类别的差异。这种情况非常戏剧化,因为它是“工作”与“无限循环”,但请注意,这std::next(it, 100)
将是一个递增it
100 次的循环,而std::ranges::next(it, 100)
将返回it + 100
,所以即使它们都“工作”,它仍然是一个显着的差异。
推荐阅读
- string - Bash 脚本比较从剪切中获得的数字
- swift - 将 Etc/GMT 时间转换为 Swift Date() 全球时间
- java - JavaFX 使用 GridPane 创建游戏板
- linux - compat_ioctl 对于 unsigned long long 数据类型不能正常工作
- html - 需要帮助将项目垂直居中在列中的剩余空间中
- python - 为什么“'y'<'x'==False”“'y'<'x'==True”并且总是返回False?
- google-apps-script - 编写应用脚本以复制并粘贴到隐藏的 Google 表格
- oauth - 基于 Angular 的 Web 应用程序与 Freshdesk 的集成
- python - 通过选择多索引 df 中的某些列将 NAN 值转换为自定义值
- php - 实现网页sql数据的动态排名结构