返回const引用无法保证线程安全,因锁在函数返回后即释放,引用仍指向原始内存,其他线程可并发修改;const不提供同步机制,亦非内存屏障;安全做法是使用带锁回调或返回值(RVO/NRVO)而非引用。

返回成员变量的const引用会暴露受保护数据
当你在类中用 const T& 返回一个被 std::mutex 保护的私有成员时,编译器确实不会报错,但锁的保护范围已经失效。因为 return current_states_; 这一行执行完后,std::lock_guard 析构、锁被释放,而返回的引用仍指向原始内存地址——调用方拿到的是“裸指针语义”的别名,后续所有读写都不再经过锁。
为什么 const 引用不能阻止竞态条件
const 只约束调用方不能通过该引用来修改对象,但它不阻止其他线程同时通过其他路径(比如另一个未加锁的接口、或直接访问共享指针)去修改同一块内存。更关键的是:它完全不参与同步机制,const 不是内存屏障,也不触发 acquire/release 语义。
- 多个线程可同时持有同一个
const T&,各自读取,但底层数据可能正被第3个线程写入 - 如果返回的是
std::vector的引用,调用方调用.data()或迭代器,就等于绕过锁直接访问原始缓冲区 - 即使你只读,若底层对象正在被另一线程移动或析构(比如容器 resize),引用会立刻变成悬垂
std::shared_ptr 包裹引用也不能自动加锁
有人试图用 std::shared_ptr<const t></const> 替代裸引用,以为能靠引用计数“延长生命周期”或“隐式同步”,这是常见误解。引用计数只管内存是否释放,不管访问是否并发安全。以下代码依然危险:
std::shared_ptr<const Eigen::VectorXd> GetStates() const {
std::lock_guard<std::mutex> lock(mtx);
return std::make_shared<const Eigen::VectorXd>(current_states_);
}问题在于:每次调用都深拷贝一份数据,性能爆炸;而且拷贝完成后锁已释放,后续对 shared_ptr 所指对象的任何操作(比如传给其他函数)仍无同步保障。
立即学习“C++免费学习笔记(深入)”;
真正安全的替代方案只有两种
要么彻底放弃暴露内部状态,要么把同步责任推给调用方——但后者几乎不可控。工程上可行的做法是:
- 提供带锁的访问回调:如
process_data([&](const auto& x) { /* read only inside lock */ }); - 返回值而非引用:让编译器有机会应用 RVO/NRVO,避免拷贝的同时也切断外部持有原始地址的可能
- 若必须返回大对象且高频调用,优先考虑 move 语义 + 移动构造函数显式标记
noexcept,比引用更可控
最易被忽略的一点:哪怕你把返回类型改成 const T& 并加了 mutable std::mutex,只要接口允许用户拿到引用后长期持有,锁就形同虚设——保护只存在于函数体内那一瞬间。


















