构造函数和析构函数调用的数量相等,可以确保没有内存泄漏

Does equal amount of constructor and destructor calls ensure no memory leaks?

本文关键字:确保 泄漏 内存 函数调用 析构 构造函数      更新时间:2023-10-16

假设我们有一个名为memoryCounter的类,它试图捕获由MyClass类引起的内存泄漏。

class memoryCounter
{
public:
    static int MyClassCount;
};
int memoryCounter::MyClassCount = 0;

假设我们在MyClass的构造函数和析构函数(以及它拥有的任何其他构造函数,也假设我们不在构造函数/析构函数之外的任何其他地方修改MyClassCount)中放入以下行:

MyClass()
{
    memoryCounter::MyClassCount++;
}
virtual ~MyClass()
{
    memoryCounter::MyClassCount--;
}

现在,我们能绝对确定如果memoryCounter::MyClassCount包含零,那么我们迄今为止分配的所有内存都被释放了,并且没有泄漏吗?或者,是否会出现这样的情况:变量将包含零,但将分配我们没有释放的内存(请考虑"MyClass"也是基类或派生类的情况)?

不,你不能。也可以有其他构造函数(至少复制构造函数)。你不算他们。

此外,static变量的销毁也不容易计数,因为它们是在main退出后销毁的

如果计数为零,则不存在MyClass的实例。无论MyClass对象是完整对象、基类子对象,还是成员子对象,它都适用。这并不一定意味着没有内存泄漏,因为MyClass本身可能会泄漏内存。

需要注意的是默认生成的复制构造函数。你说假设"它拥有的任何其他构造函数"增加你的全局计数,但很容易错过代码中没有出现的构造函数。你可以在这里应用三条规则——你定义了一个析构函数,所以你应该定义一个复制构造函数。请注意,规则还告诉您定义了一个副本分配运算符,在这种情况下不需要它。

谁说只有构造函数才能分配内存?如果某个非构造函数成员函数(静态或非静态)分配内存,而析构函数没有正确清理,则表示内存泄漏。

因此,答案是。您已经统计了通过标准构造函数创建的类实例。不多不少。

您假设MyClass(及其派生的任何东西)是正确编写的。特别是,这种泄漏不会被检测到:

class BadClass : private MyClass
{
  public:
     BadClass() { int *x = new int(5); }
}

你的计数器所做的是告诉你,每个构造都有一个破坏,这意味着没有人泄露任何"MyClass"对象。

但这并不等同于没有内存泄漏。