
函数参数是 int 还是 int&?看改不改原变量
值传递(int x)拷贝一份数据,函数里怎么改都不影响外面;引用传递(int& x)传的是原变量的别名,改它就等于直接改外面那个变量。
常见错误现象:void swap(int a, int b) { int t = a; a = b; b = t; } 调用后原变量根本没变——因为只在副本上操作。
- 需要修改调用方变量时,必须用
int&(或const int&如果只读) - 传小类型(
int、char、bool)优先值传递,没额外开销 - 传大对象(如
std::vector、自定义类)不用const T&就可能触发深拷贝,性能掉得明显
const T& 和 T&& 都能接临时对象,但用途完全不同
const T& 是“只读引用”,能绑定左值和右值(比如字面量、函数返回的临时对象),常用于避免拷贝;T&& 是“右值引用”,只绑定将亡值,核心用途是实现移动语义。
使用场景:想高效接收一个临时 std::string 参数,写 void func(const std::string& s) 安全通用;但如果想把它“搬走”内容(比如塞进成员变量),就得重载 void func(std::string&& s) 并用 std::move(s)。
立即学习“C++免费学习笔记(深入)”;
- 误把
T&&当成“万能引用”:它不接受左值,除非配合模板推导 +std::forward - 返回局部对象时,编译器通常自动启用返回值优化(RVO),不必手动
std::move返回值 -
const T&不能调用非 const 成员函数,容易编译报错:s.push_back('a')在const std::string& s下不合法
指针传参(T*)和引用传参(T&)选哪个?
引用更安全,指针更灵活。引用必须初始化且不能为 nullptr,天然排除空指针解引用风险;指针可以为空、可重指向、可做算术运算。
常见错误现象:函数声明用 void foo(int& x),但调用时传了字面量 foo(42) —— 编译失败,因为非 const 引用不能绑定右值。
- 接口设计优先用
T&或const T&,明确表达“必须传有效对象” - 需要表达“可选”语义(比如参数可不提供),用
T*或std::optional<t></t>,别用T&加默认值欺骗编译器 - 数组退化问题:
void bar(int arr[10])实际等价于void bar(int* arr),长度信息丢失;要用std::array或std::span保尺寸
结构体/类传参时,= default 的拷贝构造函数会影响值传递行为
如果类里有指针成员,又没写自定义拷贝构造函数,编译器生成的默认版本是浅拷贝——两个对象共享同一块堆内存,后续析构可能 double free。
使用场景:传一个含 std::unique_ptr 的类对象,值传递会触发移动(如果移动构造可用),否则编译失败;而引用传递完全绕过拷贝/移动逻辑。
- 只要类管理资源(文件句柄、内存、socket),就该显式定义或删除拷贝/移动操作
- 现代 C++ 中,值传递大型可移动对象未必慢,但前提是移动构造函数被正确实现且未被意外禁用(比如私有或
= delete) - 调试时发现对象析构两次或 crash,先查传参方式是否意外触发了拷贝,再确认拷贝/移动语义是否符合预期
事情说清了就结束。参数传递不是语法选择题,而是资源归属、生命周期和意图表达的综合判断。最常被忽略的,是把“能编译通过”当成“语义正确”。







