C++如何定义可外部传入或内部构造的类成员变量
问题解决思路
先分析你给出的两个方案:
- 第一个方案会默认构造
m_aObj,即便外部传入了A对象,这个内部对象也完全用不上,若A的构造成本较高,会造成不必要的资源浪费,合理性不足。 - 第二个方案用
std::shared_ptr虽能编译通过,但强制引入了共享所有权的语义,而你明确不需要共享,额外的引用计数也会带来性能开销,并非最优选择。
更优方案:用std::variant存储两种状态
C++17及以上版本可借助std::variant存储两种状态:要么是对外部A对象的引用(用std::reference_wrapper包装,因为引用无法直接存入variant),要么是自身拥有的std::unique_ptr<A>。既满足两种构造场景,又无多余开销,也不会强制共享所有权。
示例代码:
#include <variant> #include <memory> #include <functional> class A { public: void do_something() { /* 非const方法实现 */ } }; class B { public: // 构造函数1:内部构造A,所有权归B B() : m_a(std::make_unique<A>()) {} // 构造函数2:外部传入A,所有权归调用方 B(A& a) : m_a(std::ref(a)) {} void useA() { std::visit([](auto&& val) { using T = std::decay_t<decltype(val)>; if constexpr (std::is_same_v<T, std::reference_wrapper<A>>) { val.get().do_something(); } else if constexpr (std::is_same_v<T, std::unique_ptr<A>>) { val->do_something(); } }, m_a); } private: std::variant<std::reference_wrapper<A>, std::unique_ptr<A>> m_a; };
兼容旧标准方案:继承拆分两种场景
若编译器不支持C++17,可通过继承拆分B的两种场景,逻辑清晰且无需依赖新特性:
class A { public: void do_something() { /* 方法实现 */ } }; class BBase { public: virtual void useA() = 0; virtual ~BBase() = default; }; // 持有外部A的引用,所有权归调用方 class BExternal : public BBase { public: BExternal(A& a) : m_a(a) {} void useA() override { m_a.do_something(); } private: A& m_a; }; // 内部构造A,所有权归自身 class BInternal : public BBase { public: BInternal() : m_a() {} void useA() override { m_a.do_something(); } private: A m_a; };
总结
- 你原有的两个方案弊端明显,不推荐使用。
- 优先选择
std::variant方案,简洁高效,符合现代C++风格。 - 若无法使用C++17,继承拆分的方案是可靠替代。
内容的提问来源于stack exchange,提问作者kfpgk
相关产品推荐
相关产品推荐

