将参数转为数据成员:按拷贝还是右值引用接收参数?
按值传递 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
相关产品推荐
相关产品推荐

