基于右值容器创建视图是否会触发未定义行为?
问题代码
#include <iostream> #include <vector> #include <ranges> #include <algorithm> auto get_vec() { return std::vector<int> { 1, 2, 3, 4, 5, 6, 7 }; } int main() { // 1) 符合预期,返回类型为:std::ranges::dangling auto it = std::ranges::max_element(get_vec()); // 2) 视图的生命周期是否会被延长,还是会悬垂(未定义行为) auto vw = get_vec() | std::ranges::views::take(3); // 打印前3个整数 std::ranges::for_each(vw, [](const int &i) { std::cout << i << '\n'; }); }
问题描述
在语句1)中,std::ranges::max_element返回std::ranges::dangling是合理的:因为get_vec()返回右值vector,函数返回后临时对象立即销毁,迭代器指向已释放的内存,标准用dangling类型标记这种悬垂情况。
但对于语句2),原以为视图会因为引用已销毁的临时vector触发未定义行为,但实际运行正常,用valgrind和libasan也没检测到问题。请问这段代码是否属于未定义行为?使用编译器为gcc 16.0.1。
解答
这段代码确实会触发未定义行为,原因如下:
std::ranges::views::take是一个非拥有型视图适配器,它仅持有对底层range的引用,不会复制或接管原容器的所有权。get_vec()返回的是临时vector(右值),在表达式get_vec() | std::ranges::views::take(3)结束后,这个临时vector的生命周期就会终止,内存被释放。- 后续通过
vw访问原vector的元素时,视图持有的是指向已销毁对象的引用,这完全符合C++标准中“未定义行为”的定义。
至于实际运行正常、工具未检测到问题,是因为未定义行为的表现具有随机性:临时对象的内存可能还未被其他操作覆盖,所以读取时刚好能拿到原来的值,但这并不代表代码是合法的。一旦内存被复用,就可能出现崩溃、输出乱码等不可预料的结果。
内容的提问来源于stack exchange,提问作者Tootsie
相关产品推荐
相关产品推荐

