C++CLI 析构函数和终结器理解
测试类:
#pragma once
ref class Hello
{
public:
Hello();
~Hello();
!Hello();
};
/***************/
#include "Hello.h"
Hello::Hello()
{
System::Console::WriteLine("构造函数!");
}
Hello::~Hello()
{
System::Console::WriteLine("析构函数!");
}
Hello::!Hello()
{
System::Console::WriteLine("终结器:!");
}
主函数:
#include "Hello.h"
using namespace System;
int main()
{
{
Hello ^hello = gcnew Hello();
delete hello; // 显式释放
}
{
Hello h; // 这种栈对象,超过作用域会调用析构函数。也是显式释放。
}
String^ info = Console::ReadLine();
Console::WriteLine("信息:{0}", info);
GC::Collect(); // 垃圾回收
return 0;
}
上面的主函数,运行输出会这样:
构造函数!
析构函数!
构造函数!
析构函数!
如果,动态对象不显示释放:
int main()
{
{
Hello ^hello = gcnew Hello();
//delete hello; // 不显式释放
}
{
Hello h; // 这种栈对象,超过作用域会调用析构函数。也是显式释放。
}
String^ info = Console::ReadLine();
Console::WriteLine("信息:{0}", info);
GC::Collect(); // 垃圾回收
return 0;
}
输出应该这样:
构造函数!
构造函数!
析构函数!
终结器:!
经测试,Hello ^hello = gcnew Hello(); 这种动态对象,如果用 delete 显式释放,会调用析构函数。终结器是在GC回收前调用的;如果显式释放调用了析构函数,就不会再调用终结器了。所以要注意这个。 gcnew 动态调用,不显式释放,GC 回收的话会调用终结器。所以一般用下面这种方式,保证什么情况都能释放非托管内存:
Hello::~Hello()
{
// 这里释放托管资源
System::Console::WriteLine("析构函数!");
!Hello(); // 在析构函数里再调用终结器
}
Hello::!Hello()
{
// 这里释放非托管资源
System::Console::WriteLine("终结器:!");
}
C# 中一般使用IDisposable接口:
public class MyClass : IDisposable
{
private bool _disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // 防止终结器再次执行
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// 清理托管资源
}
// 清理非托管资源
_disposed = true;
}
}
// 终结器依然可以存在,作为最后的清理手段
~MyClass()
{
Dispose(false);
}
}
通过实现IDisposable接口和提供一个Dispose方法,你可以更主动、确定地管理资源的生命周期,这对于包含非托管资源(如文件句柄、数据库连接等)的对象尤为重要。
托管 C++:
ref class MyClass : public System::IDisposable
{
private:
bool disposed = false;
public:
// 实现IDisposable接口
virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// 清理托管资源
}
// 清理非托管资源
// ...
disposed = true;
// 如果是从Dispose()调用的,告诉GC不需要调用终结器
GC::SuppressFinalize(this);
}
}
// 公共Dispose方法
void Dispose()
{
Dispose(true);
GC::SuppressFinalize(this);
}
// 析构器,间接实现终结器逻辑
!MyClass()
{
Dispose(false);
}
protected:
~MyClass(){} // 这里是托管C++特有的析构函数声明,但实际清理逻辑应在Dispose中完成
};
在上述例子中,Dispose(bool disposing)方法负责实际的资源清理工作,根据disposing参数决定是否清理托管资源。!MyClass()是一个析构器,当对象被垃圾回收时,它会调用Dispose(false)来释放非托管资源。而显式的~MyClass()声明是托管C++类的一部分,但通常仅作为标记,实际的清理逻辑应集中于Dispose模式中。
浙公网安备 33010602011771号