说我有一个AbstractBaseClass
和一个ConcreteSubclass
。
以下代码创建了ConcreteSubclass,然后完全处理它并且没有内存泄漏:
ConcreteSubclass *test = new ConcreteSubclass(args...);
delete test;
但是,只要我将此指针推入向量,就会出现内存泄漏:
std::vector<AbstractBaseClass*> arr;
arr.push_back(new ConcreteSubclass(args...));
delete arr[0];
delete arr[0];
的内存泄漏比没有删除的内存泄漏少,但仍有一些内存泄露。
我做了大量的在线查看,这似乎是一个很好理解的问题 - 我正在删除指向内存的指针,但不是实际的内存本身。所以我尝试了一个基本的解引用... delete *arr[0];
,但这只是一个编译错误。我还尝试了一大堆其他引用和解引用,但每个只是给出编译器错误或程序崩溃。我只是没有找到正确的解决方案。
现在,我可以使用shared_ptr
来完成工作而没有泄漏就好了(因为我没有C ++ 11可以提升):
std::vector<boost::shared_ptr<AbstractBaseClass>> arr2;
arr2.push_back(boost::shared_ptr<AbstractBaseClass>(new ConcreteSubclass(args...)));
但是我无法使用手动方法。这不是很重要 - 使用Boost非常容易,但我真的想知道我做错了什么,所以我可以从中学习,而不仅仅是在没有发现错误的情况下移动。
我尝试通过Boost的shared_ptr模板进行跟踪,但是我不断迷失,因为每个函数都有这么多的重载,而且我发现很难跟踪每个分支。
我认为就是这个:
template<class Y>
explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete
{
boost::detail::sp_pointer_construct( this, p, pn );
}
但我一直在checked_array_delete
结束,但这可能不正确,因为它使用delete[]
。我需要深入了解
template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}
那只是打电话给delete
,没什么特别的。试图贯穿所有参考和解除引用操作符从一开始就是一场灾难。所以基本上我被卡住了,我无法弄清楚Boost是如何使它工作的,而我的代码却没有。所以回到开头,如何重新编写此代码以使删除不泄漏?
std::vector<AbstractBaseClass*> arr;
arr.push_back(new ConcreteSubclass(args...));
delete arr[0];
谢谢。
答案 0 :(得分:3)
shared_ptr
存储&#34;删除&#34;,一个辅助函数 1 ,在调用{{{{}}之前将指针强制转换回原始类型(ConcreteSubclass*
) 1}}。你还没有做到这一点。
如果delete
有一个虚拟析构函数,那么调用AbstractBaseClass
就可以了,并且与delete arr[0];
一样好用。如果它没有,那么通过基础子对象的删除是未定义的行为,并且可能导致比内存泄漏更糟糕的事情发生。
经验法则:每个抽象基类都应该有一个用户声明的(显式默认为ok)析构函数
delete (ConcreteSubclass*)arr[0];
OR
virtual
辅助功能修改或两者兼而有之。
1 您已找到实施,它是protected:
。但它使用checked_delete
- new
的返回类型进行实例化。所以它使用普通的删除,但是在指向类型checked_delete<ConcreteSubclass>(ConcreteSubclass* x)
的指针上,即使没有虚拟调度的帮助,编译器也可以找到正确的析构函数。