类A含私有构造/析构、B为友元类时,B中创建A的vector报错求助
解决C++中私有析构函数导致vector无法操作对象的问题
咱们先搞清楚为啥会出现这个error C2248的错误:
当你在B::addA里调用vecA.push_back(a)时,std::vector<A>内部会做这些操作:
- 如果当前vector的容量不够装新元素,会开辟一块更大的内存
- 把旧内存里的A对象拷贝/移动到新内存
- 销毁旧内存里的A对象(这时候必须调用A的析构函数)
- 把新的A对象拷贝到vector的内存里
但你把A的析构函数设成了私有,而std::vector<A>并不是A的友元类,它没权限调用A的私有析构函数,自然就编译失败了。
下面给你两个可行的解决方案,你可以根据自己的封装需求来选:
方案一:让std::vector成为A的友元
这是改动最小的方法,直接在A的类里加一行友元声明,允许vector访问A的私有成员:
修改后的A类代码:
class A { private: A(); A(const std::string& name, const float& num); ~A(); public: friend class B; friend class std::vector<A>; // 新增:允许vector访问A的私有成员 private: std::string name_; float num_; };
优点:不需要改其他代码,一键解决问题。
缺点:会破坏A的封装性——任何地方只要定义了std::vector<A>,都能创建、销毁A的对象,这可能违背了你原本只想让B类操作A的设计初衷。
方案二:用智能指针存储A的对象(推荐)
改用std::vector<std::unique_ptr<A>>来存储A的指针,而不是直接存A的实例。这样vector管理的是指针,销毁指针时不需要调用A的析构函数(智能指针会自动搞定),同时还能保持A的封装性,只有B能创建A的对象。
具体步骤如下:
- 修改B类的私有成员,换成智能指针的vector:
class B { public: B(); ~B(); void addA(const std::string name, const float num); private: std::vector<std::unique_ptr<A>> vecA; // 从vector<A>改成vector<unique_ptr<A>> };
- 在A类里添加
std::default_delete<A>作为友元(因为std::unique_ptr的默认删除器需要调用A的析构函数):
class A { private: A(); A(const std::string& name, const float& num); ~A(); public: friend class B; friend struct std::default_delete<A>; // 新增:允许默认删除器访问析构函数 private: std::string name_; float num_; };
- 修改B的
addA函数,用std::make_unique创建A的对象并加入vector:
void B::addA(const std::string name, const float num) { vecA.push_back(std::make_unique<A>(name, num)); }
如果你不想用std::make_unique,也可以直接用new创建对象(不过更推荐前者,更安全):
vecA.emplace_back(new A(name, num));
优点:
- 完美保持A的封装性:只有B类能创建A的对象,其他地方根本没法实例化A
- 避免了vector直接操作A的实例,减少了封装泄露的风险
- 智能指针自动管理内存,不用手动释放A的对象,省心
缺点:需要修改B类的成员类型和添加友元声明,改动比方案一大,但更符合面向对象的设计原则。
内容的提问来源于stack exchange,提问作者Hossein
相关产品推荐
相关产品推荐

