应使用引用或指针传参避免拷贝开销,只读用const引用,可修改用非const引用或指针;对象间通信须通过公有接口而非直接访问私有成员;共享数据优先用智能指针管理生命周期;跨线程访问必须加同步机制。

用引用或指针传参避免拷贝开销
如果只是想让函数内部修改另一个对象的状态,最直接的方式是把对象以 &(引用)或 *(指针)形式传入。默认按值传递会触发拷贝构造,对大对象(比如含 std::vector 或 std::string 的类)很慢,还可能意外切断对象间关联。
常见错误是写了 void func(MyClass obj) 却期望 obj 的修改能影响外部实参——这不可能,因为传的是副本。
- 用
void func(MyClass& obj)可读写原对象,但调用方必须传左值(如变量),不能传临时对象(除非是 const 引用) - 用
void func(const MyClass& obj)适合只读场景,安全且零拷贝 - 用
void func(MyClass* obj)更灵活(可传nullptr表示“无”),但需手动判空,且语义上不如引用清晰
通过成员函数暴露可控接口
两个对象之间不该直接访问彼此私有成员,而是通过公有成员函数通信。比如 A 想通知 B 状态变化,B 应提供类似 update_status() 或 on_data_ready() 这样的明确接口,而不是让 A 直接改 B.m_value。
容易踩的坑是把通信逻辑写成“上帝函数”:一个函数里同时操作 A 和 B 的所有细节,导致耦合度高、难以测试。正确做法是每个类只管自己职责,A 调用 B 的某个方法,B 内部决定怎么响应。
- 接口命名要反映意图,比如
request_shutdown()比set_flag(3)清晰得多 - 避免在接口里暴露内部数据结构(如返回
std::vector&),防止外部绕过封装直接修改 - 若需双向通信(A → B 且 B → A),考虑用回调(
std::function)或观察者模式,而非互相持有对方指针
共享数据时优先用智能指针管理生命周期
当多个对象需要访问同一份数据(比如缓存、配置、连接句柄),裸指针或原始引用无法自动处理释放时机,极易出现悬垂指针或内存泄漏。
典型错误是 A 创建对象后把裸指针给 B,A 析构了但 B 还在用——程序崩溃往往就在这儿。
- 用
std::shared_ptr<t></t>让所有权可共享,最后一个持有者析构时才释放资源 - 若只是临时借用且不参与所有权(如函数参数),用
std::shared_ptr<t> const&</t>或T&配合原始指针检查 - 避免循环引用:A 持有
shared_ptr指向 B,B 也持有一个指向 A 的shared_ptr—— 改其中一个为weak_ptr
跨线程通信必须加同步机制
如果两个对象运行在不同线程,直接读写共享变量(哪怕用了 shared_ptr)会导致未定义行为。C++ 不保证非原子操作的线程安全性。
常见现象是值偶尔“变回旧值”、计数器漏增、或者程序在优化开启时突然出错——这些往往是竞态条件的表现,不是偶发 bug,而是必然会发生。
- 基础场景用
std::mutex+std::lock_guard保护临界区,注意锁粒度别太大(别把整个函数都锁住) - 简单标志位可用
std::atomic<bool></bool>,比互斥量轻量,但仅限基本类型和满足 trivially copyable 的结构体 - 复杂交互建议用消息队列(如
std::queue+mutex封装)或专用库(如moodycamel::ConcurrentQueue)
真正麻烦的从来不是“怎么传”,而是“谁负责生命周期”和“什么时候能读/写”。这两个问题没理清,再多语法技巧也挡不住崩溃和数据错乱。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











