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

为何被移动值的引用在目标左值超出作用域后不悬空?

关于Lambda引用捕获与右值传递的悬空引用疑问

研究Lambda引用相关用法时,我遇到一个本以为会因悬空引用崩溃的场景。我原本认为main函数里传给fn_x_3的Lambda是右值,会被移动到fn_x_3函数中并绑定到左值fn上。但程序最终输出了5,我疑惑的是:当fn_x_3的右值引用重载中的fn超出作用域时,左值引用重载里捕获的引用为何没有失效?

#include <iostream>
#include <functional>


std::function<int(int)> fn_x_3(std::function<int(int, int)>& fn) {
    // capture fn by reference!
    return [&fn](int x) {
        return fn(x, 3);
    };
}

std::function<int(int)> fn_x_3(std::function<int(int, int)>&& fn) {
    // passing fn (lvalue) by reference to fn_x_3 overload
    return fn_x_3(fn);
}

int main()
{
    // call to fn_x_3(function<int(int)>&& fn), lambda "moved into" the function
    auto fn = fn_x_3([](int x, int y){ return x + y; });
    int result = fn(2);
    std::cout << result << std::endl;
    return 0;
}

问题原因解析

  • 首先要明确:当你把右值Lambda传给fn_x_3的右值引用重载时,这个重载里的fn是右值引用绑定到临时对象后产生的左值,但这个临时对象的生命周期并没有在右值重载函数结束时立即结束。
  • 在C++规则中,临时对象被绑定到函数参数的右值引用时,它的生命周期会延长到包含该函数调用的完整表达式结束。不过这里更关键的是:你在右值重载里调用了左值重载的fn_x_3(fn),此时fn作为左值引用,指向的是那个临时的std::function对象。
  • 但真正让测试结果“正常”的核心是运气(未定义行为):那个临时的std::function对象(由Lambda隐式转换而来)在main函数的auto fn = fn_x_3(...)这个表达式结束后才会销毁。而你在表达式结束前就调用了fn(2),此时临时对象还处于生命周期内,所以引用有效。但如果把fn(2)的调用放到表达式结束之后,或者编译器优化策略不同,就极大概率会触发悬空引用,导致程序崩溃或出现不可预测的结果。
  • 总结:你当前的测试结果只是巧合,这段代码本身存在严重的未定义行为,绝对不能依赖这个逻辑编写生产代码。

内容的提问来源于stack exchange,提问作者Niklas Vest

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 05:01:01