假定一个类及其所有子类只需要默认的析构函数来释放它们的资源(如果存储在精确类型的变量中(或指向精确类型的指针)),如果由基类引用,子类是否会泄漏内存类指针然后被那个指针删除?
#include <memory>
class A {
};
class B : public A {
public:
B () : pInt(new int) {}
auto_ptr<int> pInt; // this is what might leak... possibly more will though
};
void will_this_leak () {
A *pA = new B();
delete pA;
}
答案 0 :(得分:9)
“泄漏记忆”?你为什么要专门谈论泄漏记忆?
您发布的代码会产生未定义的行为。在这种情况下可能发生任何事情:内存泄漏,硬盘格式化,程序崩溃等等。
P.S。我知道那里有一个流行的都市传奇,在没有虚拟析构函数的情况下执行多态破坏“可能会泄漏内存”。我不知道是谁发明了那些废话以及为什么他们决定使用“泄漏记忆”作为可能发生的事情的主要场景。实际上,这种情况下的行为与“泄漏记忆”完全无关。行为很简单。
从实际的角度来看,在你的特定情况下很明显你的auto_ptr
的析构函数没有真正的机会被调用,所以auto_ptr
所拥有的内存肯定会被泄露。但同样,这是代码中最少的问题。
答案 1 :(得分:4)
它们是否可以泄漏并不重要。 C ++标准规定,如果基础没有虚拟析构函数,则通过基指针删除派生类是未定义的行为。具体来自5.3.5 / 3:
在第一个替代(删除对象)中,如果是静态类型的 操作数与其动态类型不同,静态类型应为 操作数的动态类型的基类和 静态类型应具有虚拟析构函数或行为未定义。
所以一旦你做了这样的删除,你的程序就处于一个未定义的状态,所有关于泄漏的问题都没有实际意义。
答案 2 :(得分:1)
是的,这会泄漏。当你删除A *时,它会调用~A()。由于~A()不是虚拟的,因此不会知道~B()也需要调用。
当然,假设B继承自A.我猜这是你问题中的错字 - 代码不能编译:)
答案 3 :(得分:1)
截至目前的代码展示 undefined-behavior 。
如果操作数的静态类型是 那么与动态类型不同 静态类型成为基类 它的析构函数必须是虚拟。否则行为未定义。
#include <memory>
class A {
public :
virtual ~A() {} // This makes the derived sub-object destruction first
};
class B : public A {
public:
B () : pInt(new int) {}
auto_ptr<int> pInt;
/* There is no need to write any custom destructor
in this case. auto_ptr will effectively handle deallocating
the acquired resources from free store.
*/
};
void will_this_leak () {
A *pA = new B();
delete pA;
}
通过上述更改,不应存在任何未定义的行为或内存泄漏。