C++20初始化时将类A成员变量共享给成员实例B、C的方案选型
当前使用C++20环境,需要在类A初始化时将自身的成员变量共享给其成员实例B和C。要求不采用getter/setter、单例、依赖注入等方式,计划通过在B、C的构造函数中传递数据,让B、C以引用、指针等方式持有共享数据。
额外规定:B、C始终作为A的成员被初始化,且A是数据的最终所有者,当A销毁时共享数据需随之释放。在此前提下,以下四种方案中哪些符合规范且能保证封装性?
- A以
shared_ptr存储并传递数据,B、C以shared_ptr持有数据; - A以普通变量存储数据,传递
void指针,B、C以void指针持有; - A以普通变量存储数据,传递引用,B、C以引用持有;
- A以普通变量存储数据,传递裸指针,B、C以裸指针持有;
伪代码:
class B { private: // 用于持有共享数据的变量 }; class C { private: // 用于持有共享数据的变量 }; class A { private: // 需要共享数据的成员实例 B b; C c; // 待共享的数据 SomeDataType first; SomeDataType second; public: A() : b{first, second}, c{first} { } };
方案1:不符合要求。
shared_ptr的设计核心是共享所有权,但题目明确A是数据的唯一最终所有者,用shared_ptr会让B、C也拥有数据的所有权,违背了"A是最终所有者"的核心规则。而且A的成员变量本身由A管理生命周期,完全没必要用shared_ptr做冗余的所有权管理,也破坏了封装性。方案2:不符合要求。
void*会丢失类型信息,使用时必须强制转换,既违反C++的类型安全原则,也彻底破坏封装性——B、C需要知晓原始数据类型才能正确操作,相当于暴露了A的内部数据细节,还极易引发未定义行为。方案3:符合规范且保证封装性。由于B、C是A的成员,它们的生命周期与A严格绑定,A的成员变量
first、second的生命周期也和A完全一致,因此传递引用是安全的。引用仅作为数据的别名,不会转移所有权,A始终是数据的唯一所有者。同时B、C的引用是私有成员,外部无法访问,完全符合封装要求。注意:A的成员声明顺序必须将first、second放在b、c之前,避免用未初始化的对象初始化引用。方案4:符合规范且保证封装性。和方案3逻辑一致,裸指针在这里是安全的——B、C的生命周期与A绑定,A销毁时会先销毁
b、c,再销毁first、second,不会出现悬空指针问题。裸指针同样不会转移所有权,A保持数据的唯一所有权,且B、C的指针为私有成员,外部无法访问,保证了封装性。同样需要注意成员声明顺序,确保first、second先于b、c初始化。
符合规范且能保证封装性的是方案3和方案4。
内容的提问来源于stack exchange,提问作者spaL

