在 C++ 开发中,一个经常让人困惑的问题是:
函数参数到底该写
T、T&,还是const T&?
很多人只记住一句话:
“大对象用 const 引用,小对象用值传递”,
但背后的逻辑如果不理解,实际写代码时还是会犹豫。
这篇文章我们从性能、语义、工程实践三个角度,把参数传递方式一次讲清楚。
一、C++ 三种常见参数形式
1. 值传递(Pass by Value)
void f(T x);特点:
- 会拷贝一份对象
- 函数内部改
x,不会影响外部 - 简单直接
适用场景:
- 小类型(int / double / bool / enum)
- 函数需要“收下这份数据”
- 要存入成员变量 / 容器
2. 引用传递(Pass by Reference)
void f(T& x);特点:
- 不拷贝,直接操作原对象
- 可以修改调用者的数据
适用场景:
- 明确要修改调用者对象
- 工具函数 / 算法函数 / swap / normalize 等
3. 常量引用(Pass by Const Reference)
void f(const T& x);特点:
- 不拷贝
- 不允许修改
- 性能好 + 语义清晰
适用场景:
- 大对象只读访问
- 打印 / 比较 / 计算 / 日志 / 序列化
- std::string / vector / map / 自定义类
二、为什么不用const T(值传 const)?
很多人会写:
void f(const std::string s);这其实意义不大,因为:
- 仍然会拷贝
- const 只限制函数内部
- 外部对象本来就不会被影响
所以:
const T不能省拷贝,const T&才能省拷贝。
三、性能视角:什么时候会浪费资源?
大对象
void f(std::string s); // 会拷贝 void f(const std::string& s); // 不拷贝拷贝 string / vector 可能涉及:
- 内存分配
- 数据复制
- 构造析构
这是真正的资源浪费。
小对象
void f(int x); // 推荐 void f(const int& x); // 没必要原因:
- int 只有 4 字节
- 引用反而传 8 字节地址
- CPU 寄存器传值更快
四、现代 C++ 的一个重要写法:值传 + move
当函数需要保存参数时,推荐这样写:
class User { std::string name; public: void setName(std::string n) { name = std::move(n); } };优点:
- 左值调用:会拷贝
- 右值调用:直接移动
- 接口统一,调用舒服
这是现代 C++ 很常见的工程写法。
五、工程实践决策表
三个判断问题
1. 是否需要修改调用者?
是 →
T&否 → 继续
2. 是否是小类型?
是 →
T否 → 继续
3. 是否要保存参数?
是 →
T + move否 →
const T&
六、快速记忆口诀
可以直接背这一句:
改它:T&
小的:T
大的只读:const T&
要收下:T + move
七、典型示例对照
小类型
void setAge(int age);大对象只读
void print(const std::string& s);修改对象
void normalize(std::vector<int>& v);存储对象
void setName(std::string name);八、总结
C++ 参数传递的本质不是语法问题,而是:
- 性能
- 语义表达
- 工程可维护性
真正的原则不是死记硬背,而是理解:
我是“借来看一眼”,
还是“要动它”,
还是“要收下它”。
理解这一点,你写出的函数签名就会自然、专业、工程化。