现代c++ 中定义方法参数的时候,什么时候传递指针,什么时候使用引用,什么时候使用值?
先说结论:想共享用引用,想可空/重指向用指针,想孤立副本用值。
1. 值传递 (T)
场景
- 函数内部需要一份独立副本(修改不影响调用者)
- 或者类型足够小(
int、double、char、小型 POD),拷贝成本 ≈ 0
示例
int add(int a, int b); // 原生类型
double norm(Vector3 v); // Vector3 仅 3 个 double,64 字节以内可接受
注意
C++17 后对于"大对象"编译器会强制复制省略(RVO),但语义上仍是"我拿到了副本"。
2. const 引用 (const T&)
场景
- 只读大对象(
std::string、容器、复杂类),避免深拷贝 - 调用者保证对象存在,且不为空
- 不需要中途换指向
示例
bool login(const std::string& user, const std::string& pwd);
size_t countLines(const std::vector<int>& data);
3. 非 const 引用 (T&)
场景
- 函数必须把结果写回调用者(输出参数)
- 调用者保证对象存在,且不为空
- 语义就是"我替你改"
示例
void split(const std::string& src, std::vector<std::string>& out);
void normalize(Vector3& v); // 原地修改
4. 裸指针 (T*)
满足以下任一即可选指针:
- 对象可能不存在 → 用
nullptr表示 - 需要中途重指向另一对象
- 与 C 接口或旧库交互,它们只认指针
- 动态多态,需要基类指针
示例
void draw(Shape* p); // 可能为空,也可能指向子类对象
void freeResource(Resource* r); // if (r) delete r;
提示
现代 C++ 优先用智能指针管理生命周期,裸指针只扮演"可选观察"或"非拥有"角色。
5. 智能指针
| 类型 | 语义 | 示例场景 |
|---|---|---|
unique_ptr<T> |
独占所有权 | 工厂函数把对象交给调用者 |
shared_ptr<T> |
共享所有权 | 需要延长生命周期的观察者 |
weak_ptr<T> |
非拥有观察 | 打破 shared_ptr 循环引用 |
示例
std::unique_ptr<FILE, decltype(&fclose)>
takeOwnership(const char* path); // 转移所有权
void observe(std::shared_ptr<Config> cfg); // 只观察,生命期由别人托管
6. 一张速查表
| 形参形式 | 可空 | 可重指向 | 拷贝成本 | 推荐场景 |
|---|---|---|---|---|
T |
❌ | ❌ | 高* | 小对象或需要独立副本 |
const T& |
❌ | ❌ | 极低 | 只读大对象 |
T& |
❌ | ❌ | 极低 | 输出参数,调用者保证存在 |
T* |
✅ | ✅ | 极低 | 可空、重指向、多态、C 接口 |
smart_ptr<T> |
✅ | ✅ | 低 | 共享/转移所有权 |
*"高"是相对于引用而言;对可移动的大对象,C++17 后实际常常零成本。
7. 三句口诀选型
写函数签名前,按顺序问自己:
- 我要空吗?
- 我要换指向吗?
- 我要拷贝吗?

浙公网安备 33010602011771号