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

将参数转为数据成员:按拷贝还是右值引用接收参数?

按值传递 vs 右值引用传递的性能差异与实践选择

用户提供的示例代码:

#include <string>
#include <cstdio>

struct efficient_entity
{
    efficient_entity(std::string&& str)
        :   str_ { std::move(str) }
    { }

    std::string str_;
};

struct inefficient_entity
{
    inefficient_entity(std::string str)
        :   str_ { std::move(str) }
    { }

    std::string str_;
};


int main()
{
    std::string create_here = "I guarantee you this string is absolutely huge!";
    efficient_entity(std::move(create_here));
    inefficient_entity(std::move(create_here));
}

性能差异分析

先明确两种实现的实际开销:

  • 传入右值(如std::move后的对象或临时字符串):
    • efficient_entity:参数是右值引用,直接通过std::move转移到成员变量,仅1次std::string的移动构造(O(1)开销,仅拷贝指针等元数据,无内存分配或字符拷贝)。
    • inefficient_entity:先通过移动构造创建参数str,再移动到成员变量,共2次移动构造。但std::string的移动成本极低,两次移动的总开销几乎可以忽略,和单次移动没有可感知的差异。
  • 传入左值:
    • efficient_entity:没有匹配的左值重载,直接编译失败——这意味着你必须额外编写左值引用版本的构造函数,当参数数量增多时,重载的数量会指数级增长(比如2个字符串参数就需要4个重载),维护成本极高。
    • inefficient_entity:先拷贝构造参数str,再移动到成员变量,开销是1次拷贝构造(O(n),n为字符串长度)+1次移动构造(O(1))。而如果写左值引用的重载,开销是1次拷贝构造(直接从左值到成员),两者的差异仅多了一次无足轻重的移动操作。

编译器优化的影响

编译器不会把两次移动构造合并成一次,但这根本不重要——因为std::string的移动构造本身就是几行指针赋值的操作,没有任何昂贵的操作。即使不优化,两次移动的开销也完全可以忽略,不会成为性能瓶颈。

是否需要担忧性能?

完全不需要。按值传递的实现方式优势远大于那点几乎不存在的性能差异:

  • 代码更简洁,无需维护大量重载函数;
  • 调用方无需关心参数传递的细节,传左值或右值都能正常工作;
  • 仅当处理的是移动成本极高的类型(这种类型在C++标准库和现代代码中几乎不存在,因为移动语义的设计目标就是低成本),才需要考虑右值引用的方式。

CppCon演讲线索

你提到的CppCon演讲应该是Scott Meyers的《Back to the Basics! Essentials of Modern C++ Style》,或是Herb Sutter的相关议题(如《GotW #91 Solution: Smart Pointer Parameters》的衍生内容),这些演讲都深入讨论了按值传递与右值引用传递的权衡,重点强调了在大多数场景下,按值传递的简洁性和可维护性优先于那点微乎其微的性能差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 05:25:53