单例:为什么不需要删除并且看不到析构函数调试消息

Singleton: why no need to delete and can't see destructor debug message

本文关键字:看不到 析构函数 调试 消息 为什么 不需要 删除 单例      更新时间:2023-10-16

我的讲师说我们不需要删除在堆中创建的单例对象,因为当超出范围时,它的内存会被释放并自动删除。

是因为编译器对静态对象的处理不同,所以我们不需要担心从堆中删除这个对象吗?

在下面的代码中,我认为主要是指针超出了范围,而不是堆中的对象本身,但在某个时刻,如果确实为该对象释放了内存,则应该调用对象的析构函数?

我还尝试在main中添加成员函数DeleteObject,但我看不到正在调用堆中对象的析构函数。

但是仍然看不到析构函数在屏幕上显示消息。

#include <iostream>
using namespace std;
class Singleton {
public:
static Singleton* GetInstance();
void Show() { cout << "Single object"; }
void DeleteObject();
~Singleton();
private:
static Singleton* psingleton;
Singleton();
};
void Singleton::DeleteObject() {
delete psingleton;
}
Singleton::~Singleton() {
cout << "nnAt Destructor";
}
Singleton* Singleton::psingleton = 0;
Singleton::Singleton()
{
//do stuff
}
Singleton* Singleton::GetInstance() {
if (psingleton = NULL ) {
psingleton = new Singleton();
}
return psingleton;
}
int main()
{
Singleton::GetInstance()->Show();
Singleton::GetInstance()->DeleteObject();//another try
return 0;
}

会期望对象析构函数在屏幕上显示一条消息,因为它被调用了。

那是因为您有一个bug。这是

Singleton* Singleton::GetInstance() {
if (psingleton = NULL) {
psingleton = new Singleton();
}
return psingleton;
}

从不生成对象,因为psingleton = NULL总是被广播到false。您想要的是if (psingleton == NULL) {

有了这个修复,我在MSVC中的输出是:

单对象

在Destructor

。。。这是因为对Singleton::GetInstance()->DeleteObject();的调用,而不是因为程序已经结束。


我认为是指针超出了main的范围,而不是对象本身,但在某个时刻如果确实为此释放了内存,则应该调用对象对象

你是对的。堆上的对象不会超出范围,并且不会仅从程序结束时调用析构函数。

我的导师说我们不需要删除在堆中创建的单例对象,因为当超出范围时,它的内存会被释放并自动删除。

是因为编译器对静态对象的处理不同,所以我们不需要担心从堆中删除这个对象吗?

您的指导老师搞错了。动态分配的对象(例如,使用运算符new创建的对象)只有在被特定地销毁(例如使用相应的运算符delete)时才会被释放。

指向对象的指针是否为静态变量并不重要。

在大多数现代操作系统中,当程序终止(正常或异常)时,操作系统会回收程序使用的内存。但是,这不会导致调用动态分配对象的析构函数。如果您依赖于被调用的析构函数(而不是被回收的内存),那么您需要确保在程序终止之前调用析构函数。例如,如果一个对象管理一个系统资源,例如互斥锁。

C++标准不要求在程序终止时释放动态分配的对象。而且大多数(如果不是全部的话)现代操作系统(unix、windows等)都会回收现有进程的内存回收内存,不会调用动态分配对象的析构函数。

还有一些操作系统不需要回收终止程序的内存——尽管现在这种系统的使用不太常见,但在它们上运行的程序需要经过专门设计,以确保它们正确释放所有动态分配的对象。

当然,有一些技术可以用来确保释放动态分配的对象(例如,将指向这些对象的指针存储在std::unique_ptr中)。静态std::unique_ptr<T>将在程序终止时被销毁,其析构函数将自动销毁其管理的任何动态分配的对象。(当然,有一些方法可以防止这种情况发生,例如调用std::abort())。

我认为你的老师错了,上面的代码会导致Singleton对象的内存泄漏