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

clang-tidy的modernize-pass-by-value建议仅适用于C++20及以上吗?

C按值传递并移动的性能变化:C20的关键改进

核心结论

clang-tidy的modernize-pass-by-value建议并非仅在C20及以上才"正确",但**在C20及以上,该建议对左值(lvalue)和右值(rvalue)都能保证最优性能**;而在C++17及更早版本中,按值传递并移动确实会给左值带来额外的性能开销。

C++17中按值传递左值的性能损耗原因

当传递const左值给按值传递的构造函数时(比如示例中的PassByValueAndMove),C++17及之前的编译器必须执行两步操作:

  • 先拷贝构造函数的参数(从传入的const左值);
  • 再移动构造类的成员变量(从函数参数)。

虽然移动操作的开销极小,但编译器无法消除中间的参数对象——因为C++17的强制拷贝消除仅适用于纯右值(prvalue,比如临时对象),命名的函数参数属于泛左值(glvalue),无法被省略。相比之下,按const引用传递的构造函数(PassByReferenceAndCopy)只需要直接拷贝构造成员变量,少了中间对象的构造/析构成本,因此在基准测试中表现更快。

C++20的关键优化:消除按值传递左值的额外开销

C++20放宽了拷贝消除的限制,允许编译器将函数参数的拷贝构造与成员的移动构造合并。具体来说,当函数参数被立即用于移动构造类成员时,编译器可以直接将实参的内容拷贝到成员变量的内存位置,完全省略中间的参数对象。这使得:

  • 按值传递并移动的代码路径,与按const引用传递的代码路径在性能上完全一致;
  • 同时保留了对右值的高效支持(直接移动,无需额外重载)。

这种优化由编译器自动实现,无需开发者做任何额外操作,因此在C++20及以上的基准测试中,BM_PassLvalueByValueAndMove的性能与BM_PassLvalueByReferenceAndCopy完全持平。

基准测试代码

#include <benchmark/benchmark.h>

#include <string>
#include <utility>

struct PassByValueAndMove
{
    explicit PassByValueAndMove(std::string string)
        : m_string(std::move(string))
    {
    }

    std::string m_string;
};

struct PassByReferenceAndCopy
{
    explicit PassByReferenceAndCopy(const std::string& string)
        : m_string(string)
    {
    }

    std::string m_string;
};

struct PassBoth
{
    explicit PassBoth(std::string&& string)
        : m_string(std::move(string))
    {
    }

    explicit PassBoth(const std::string& string)
        : m_string(string)
    {
    }

    std::string m_string;
};

static void BM_PassRvalueByReferenceAndCopy(benchmark::State& state)
{
    for (auto _ : state)
    {
        static_cast<void>(_);

        {
            PassByReferenceAndCopy instance("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
            benchmark::DoNotOptimize(instance);
        }
    }
}

BENCHMARK(BM_PassRvalueByReferenceAndCopy);

static void BM_PassRvalueByValueAndMove(benchmark::State& state)
{
    for (auto _ : state)
    {
        static_cast<void>(_);

        {
            PassByValueAndMove instance("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
            benchmark::DoNotOptimize(instance);
        }
    }
}

BENCHMARK(BM_PassRvalueByValueAndMove);

static void BM_PassLvalueByReferenceAndCopy(benchmark::State& state)
{
    for (auto _ : state)
    {
        static_cast<void>(_);

        {
            const std::string      dummy_string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
            PassByReferenceAndCopy instance(dummy_string);
            benchmark::DoNotOptimize(instance);
        }
    }
}

BENCHMARK(BM_PassLvalueByReferenceAndCopy);

static void BM_PassLvalueByValueAndMove(benchmark::State& state)
{
    for (auto _ : state)
    {
        static_cast<void>(_);

        {
            const std::string  dummy_string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
            PassByValueAndMove instance(dummy_string);
            benchmark::DoNotOptimize(instance);
        }
    }
}

BENCHMARK(BM_PassLvalueByValueAndMove);

static void BM_PassRvalueToStructOfferingBoth(benchmark::State& state)
{
    for (auto _ : state)
    {
        static_cast<void>(_);

        {
            PassBoth instance("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
            benchmark::DoNotOptimize(instance);
        }
    }
}

BENCHMARK(BM_PassRvalueToStructOfferingBoth);

static void BM_PassLValueToStructOfferingBoth(benchmark::State& state)
{
    for (auto _ : state)
    {
        static_cast<void>(_);

        {
            const std::string dummy_string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
            PassBoth          instance(dummy_string);
            benchmark::DoNotOptimize(instance);
        }
    }
}

BENCHMARK(BM_PassLValueToStructOfferingBoth);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 22:24:55