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

为何轻量函数中短参数传值比传const引用更慢?

短结构体传值vs传const&的性能反常现象分析

背景与测试代码

常规观点认为,短参数(sizeof(X) <= 16)应采用传值而非const&方式传递,因为值可通过寄存器传递,而引用以指针实现,会强制内存访问。我通过一个简短测试量化该差异:

结构体定义(struct.h)

struct X
{
unsigned long fill=0;
unsigned long x=0;
};

测试函数(functions.cpp)

bool struct_by_value(X x)
{
    return x.x < 17;
}

bool struct_by_cref(X const& x)
{
    return x.x < 17;
}

主测试代码(main.cpp)

int main()
{
    size_t N = 1UL << 32;
    X x;
    double diff = 0;
    auto start = clk::now();
    for (unsigned long i; i < N; i++){
        struct_by_cref(x);
    }
    auto end = clk::now();
    std::cout << "cref: " << secs(end-start) << std::endl;    
    start = clk::now();
    for (unsigned long i; i < N; i++){
        struct_by_value(x);
    }
    end = clk::now();
    std::cout << "value: " << secs(end-start) << std::endl;
 
    start = clk::now();
    for (x.x = 0; x.x < N; x.x++){
        struct_by_cref(x);
    }
    end = clk::now();
    std::cout << "cref: " << secs(end-start) << std::endl;    

    start = clk::now();
    for (x.x = 0; x.x < N; x.x++){
        struct_by_value(x);
    }
    end = clk::now();
    std::cout << "value: " << secs(end-start) << std::endl;
 }

编译结果与汇编代码

使用g++-12.2.0 -O2编译后,两个函数的汇编代码如下:

struct_by_value的汇编

_Z15struct_by_value1X:
.LFB0:
    .cfi_startproc
    cmp rsi, 16
    setbe   al
    ret
    .cfi_endproc

struct_by_cref的汇编

_Z14struct_by_crefRK1X:
.LFB1:
    .cfi_startproc
    cmp QWORD PTR 8[rdi], 16
    setbe   al
    ret
    .cfi_endproc

可以看到struct_by_cref存在明显的内存访问操作。

测试结果(i7-10850H机器)

  1. 固定结构体的循环测试
    以下两个循环的运行时间均约为6.5秒,多次运行的误差大于传值与传引用的性能差异:

    for (unsigned long i; i < N; i++){
        struct_by_cref(x);
    }
    

    和

    for (unsigned long i; i < N; i++){
        struct_by_value(x);
    }
    
  2. 修改结构体成员的循环测试
    以下两个循环的运行时间分别约为7.2秒(传引用)和7.4秒(传值),传值调用始终比传引用慢约0.2秒:

    for (x.x = 0; x.x < N; x.x++){
        struct_by_cref(x);
    }
    

    和

    for (x.x = 0; x.x < N; x.x++){
        struct_by_value(x);
    }
    

疑问与初步分析

第一个测试的原因不难解释:结构体从未改变,长且紧凑的循环中分支预测效果良好,加载操作可提前执行,且内存吞吐量和执行端口远未饱和,因此传值与传const引用之间没有性能差异。

但第二个测试令人困惑:

  • 传const引用调用时,每次迭代中x.x需在main函数中写入内存,再在struct_by_cref中读取;
  • 传值调用中整个结构体理论上可驻留在寄存器中,无需内存操作。

由于值刚写入内存就被读取,无法进行预取。是否存在CPU将连续的内存存/取操作替换为寄存器间移动的优化?但为何传值版本反而更慢?按常理它本应全程使用寄存器。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 10:17:17