You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于右值容器创建视图是否会触发未定义行为?

问题代码
#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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 16:24:49