C++中类存储unique_ptr引用的最优最直观实现方式是什么?
这个问题的选择核心取决于你的业务场景约束,没有绝对通用的最优解,但可以根据所有权语义、生命周期保证、性能要求给出明确的优先级:
优先方案1:存储引用(满足以下约束时是首选)
如果你能同时满足以下3个条件:
- Bar的生命周期严格短于Foo的生命周期
- Foo的
vec_不会执行会导致元素引用/指针失效的操作:比如删除对应位置的元素、vector扩容(如果是预分配足够空间的静态vector则无此问题) - 不需要在Bar构造完成后修改它指向的对象
那你甚至不需要存储std::unique_ptr<SomeClass>&,直接存储SomeClass&语义更清晰:
struct Bar { Bar(SomeClass& ref) : ref_(ref) {} SomeClass& ref_; };
这个方案零性能开销,所有权语义明确:Bar仅临时借用对象,完全不涉及所有权,是最符合你最初设计的方案。
优先方案2:Foo存储shared_ptr + Bar存储weak_ptr(存在生命周期不确定风险时的首选)
如果你无法完全满足上述约束,比如:
- Bar的生命周期可能长于Foo
- Foo的
vec_会动态增删元素,无法保证Bar指向的元素一直存在 - 需要在Bar运行时修改指向的对象
那这个方案是最优选择:
// Foo的vec_改为shared_ptr class Foo { public: ... private: std::vector<std::shared_ptr<SomeClass>> vec_; }; // Bar存储weak_ptr struct Bar { std::weak_ptr<SomeClass> ref_; };
需要访问对象时调用weak_ptr::lock()判断对象是否存活,完全避免悬空访问的风险。你担心的shared_ptr性能开销在99%的业务场景下完全可以忽略,只有在每秒百万次以上智能指针拷贝的极端高频场景才会有可感知的影响。虽然Foo是唯一的实际所有者,但为了运行时的安全检查,这点性能成本的付出是完全值得的,且weak_ptr的语义非常清晰:Bar只是观察者,不持有任何所有权。
不推荐的方案
- Bar存储shared_ptr:完全违背了你设计中「Foo是唯一所有者」的语义,Bar如果存活时间超过Foo,会导致对象无法被正常释放,延长对象生命周期,除非你主动修改设计接受共享所有权,否则不要用这个方案。
- Bar存储原始指针:你对这个方案的顾虑是对的,它没有任何生命周期保护,一旦出现悬空访问就是未定义行为,排查难度极高,除非你在极端性能瓶颈场景,且能100%保证不会出现悬空,否则不要选择。
内容的提问来源于stack exchange,提问作者JensB
相关产品推荐
相关产品推荐

