传值会完整拷贝对象,开销大且无法修改原变量;传引用不拷贝但必须绑定左值且不可为空;const引用兼顾性能与灵活性;返回局部对象应传值而非引用,避免悬垂引用。

传值时对象会被完整拷贝,开销大且无法修改原变量
当你写 void func(MyClass obj),编译器会调用 MyClass 的拷贝构造函数创建一份独立副本。这意味着:
- 修改 obj 内部成员不会影响调用方的原始对象
- 如果 MyClass 含有大数组、动态内存或复杂嵌套结构,拷贝成本显著上升
- 若类没有定义拷贝构造函数(或被 = delete),传值会直接编译失败
- 移动语义(MyClass&&)可缓解部分问题,但不改变“传值=拷贝”这一本质
传引用必须绑定到左值,且默认不允许空引用
void func(MyClass& obj) 传递的是原对象的别名,不触发拷贝:
- 修改 obj 等价于修改原始变量
- 参数必须是具名变量(如 MyClass x;)、不能是临时对象(如 func(MyClass()) 会报错)
- 引用本身不可为空,不需要检查 nullptr,但也因此无法表示“可选”语义
- 若需接受临时对象,改用常量右值引用:const MyClass&& obj,但仅限读取
const 引用既能避免拷贝又能接收临时对象
写成 void func(const MyClass& obj) 是最常用的安全模式:
- 不拷贝,性能好
- 可绑定左值(MyClass x; func(x);)和右值(func(MyClass{1,2});)
- 编译器允许隐式转换后绑定(如 func(42) 若存在 MyClass(int) 构造函数)
- 但函数内部不能修改 obj 成员,除非该成员被声明为 mutable
- 注意:如果函数内部需要修改逻辑状态,又想复用这个签名,得靠 mutable 或重新设计接口
返回局部对象时,优先用值返回而非引用
常见错误是返回局部变量的引用:MyClass& bad() { MyClass x; return x; } —— 这会产生悬垂引用,运行时行为未定义。正确做法:
- 直接返回值:MyClass good() { MyClass x; return x; },现代编译器基本都会启用 RVO/NRVO 优化,避免多余拷贝
- 若对象极大且移动代价仍高,考虑用智能指针包装后返回(如 std::unique_ptr<myclass></myclass>)
- 返回引用只适用于静态变量、类成员或函数参数传入的引用,且必须确保生命周期长于调用方使用期
传引用看着省事,但生命周期管理比传值敏感得多;传值安全但可能慢——真正难的不是语法,是判断哪个变量在哪儿被谁持有、什么时候销毁。


















