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

函数指针中使用右值引用作为参数的优势是什么?

关于std::function右值引用传参的优势

我在代码中看到了这样的函数写法:

void subMyCallback3(MyCallback&& callback) {
    callback(1);
}

于是写了测试代码验证,但没发现它和普通传参的明显区别:

测试代码:

#include <iostream>
#include <functional>
#include "stdio.h"

using namespace std;

using MyCallback = std::function<void(int x)>;

void subMyCallback1(MyCallback callback) {
    printf("%p\n", &callback);
    callback(1);
}


void subMyCallback3(MyCallback&& callback) {
    printf("%p\n", &callback);
    callback(1);
}

int main() {
    auto func = [](int x) {
        std::cout << x << std::endl;    
    };
    printf("%p\n", &func);
    subMyCallback1(func);
    subMyCallback3(std::move(func));
    return 0;
}

输出结果:

0x7fff8ade477f 
0x7fff8ade4780 
1
0x7fff8ade4780 
1

请问使用右值引用作为std::function参数的优势是什么?


核心优势解析

你的测试例子用的是空捕获lambda,std::function的拷贝成本极低,所以看不出差异。但在实际业务场景中,右值引用传参有两个关键价值:

  • 避免不必要的拷贝开销
    std::function内部会存储可调用对象(比如带捕获的lambda、绑定了对象成员的函数器)。如果捕获的是大对象(比如std::vector<int>、自定义的重型类实例),传值调用会触发整个std::function的拷贝,包括内部捕获对象的拷贝,带来明显的性能损耗。而右值引用可以直接转移std::function的内部资源所有权,完全避免拷贝操作。

    举个实际场景的例子:

    void pass_by_value(std::function<void()> f) { f(); }
    void pass_by_rvalue_ref(std::function<void()>&& f) { f(); }
    
    int main() {
        std::vector<int> big_data(1000000, 1);
        auto func = [big_data]() { /* 使用big_data做计算 */ };
    
        // 传值:拷贝整个big_data到std::function内部,开销极大
        pass_by_value(func);
        // 右值引用:转移func的内部资源,无拷贝开销
        pass_by_rvalue_ref(std::move(func));
    }
    
  • 支持仅可移动的可调用对象
    有些可调用对象是只能移动不能拷贝的,比如捕获了std::unique_ptr的lambda。这种情况下,传值调用会直接编译报错,而右值引用可以接收这类对象并正常使用。

    例子:

    void pass_by_rvalue_ref(std::function<void()>&& f) { f(); }
    
    int main() {
        auto ptr = std::make_unique<int>(42);
        // 捕获unique_ptr,该lambda仅可移动
        auto func = [ptr = std::move(ptr)]() { std::cout << *ptr << std::endl; };
    
        // pass_by_value(func); // 编译错误:unique_ptr不可拷贝
        pass_by_rvalue_ref(std::move(func)); // 正常运行,输出42
    }
    

另外补充:你测试中看到的地址相同是栈地址分配的巧合——右值引用本身是函数形参的引用,它的栈地址刚好和传值的形参地址重合,不代表两者没有拷贝差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 02:40:38