我的指导者说,我们不需要删除在堆中创建的单例对象,因为当超出范围时,其内存将被释放并自动删除。
是不是编译器对静态对象的处理方式有所不同,我们不必担心从堆中删除此对象?
在下面的代码中,我认为是指针超出了main范围的范围,而不是堆本身中的对象,但是在某些时候,如果确实为此对象释放了内存,则应调用对象的析构函数?
我也尝试在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 << "\n\nAt 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;
}
希望对象析构函数在屏幕上显示一条消息,因为它被调用了。
答案 0 :(得分:3)
那是因为您有一个错误。这里
Singleton* Singleton::GetInstance() {
if (psingleton = NULL) {
psingleton = new Singleton();
}
return psingleton;
}
永远不会创建对象,因为psingleton = NULL
总是强制转换为false
。相反,您想要的是if (psingleton == NULL) {
。
通过此修复程序,MSVC中对我的输出为:
单个对象
在Destructor中
...这是因为调用了Singleton::GetInstance()->DeleteObject();
,而不是因为程序已结束。
我认为这是超出main范围的指针,而不是 对象本身在堆中,但在某些时候 如果确实为此释放了内存,则应调用对象 对象?
您是正确的。堆上的对象不会超出范围,并且仅从程序结尾不会调用析构函数。
答案 1 :(得分:2)
我的指导者说,我们不需要删除在堆中创建的单例对象,因为当超出范围时,其内存将被释放并自动删除。
是不是编译器对静态对象的处理方式有所不同,我们不必担心从堆中删除此对象?
您的教练有误。动态分配的对象(例如,使用操作符new
创建的对象)只有在被专门销毁(例如,使用相应的操作符delete
)时才会释放。
指向对象的指针是否是静态变量都没关系。
对于大多数现代操作系统,确实发生的情况是,操作系统将在程序终止(正常或异常)时回收该程序使用的内存。但是,这不会导致调用动态分配的对象的析构函数。如果您依赖于调用析构函数(而不是回收内存),则需要确保在程序终止之前调用析构函数。例如,如果对象管理系统资源(例如互斥体)。
C ++标准不需要在程序终止时释放动态分配的对象。而且,大多数(如果不是全部)确实会回收现有进程内存的现代操作系统(unix,windows等)都将回收内存,而不会调用动态分配对象的析构函数。
也有一些操作系统不费心去回收终止程序的内存-尽管这种系统的使用现在已经不那么普遍了,但在它们上面运行的程序需要专门设计以确保它们正确释放所有动态分配的对象。
当然,可以使用一些技术来确保释放动态分配的对象(例如,将指向这些对象的指针存储在std::unique_ptr
中)。静态std::unique_ptr<T>
将在程序终止时被销毁,其析构函数将自动销毁它管理的任何动态分配的对象。 (当然,有防止这种情况发生的方法,例如通过调用std::abort()
。)
答案 2 :(得分:1)
我认为您的教练错了,上面的代码将导致Singleton对象的内存泄漏