科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件C++:最强大的.NET语言之内存与资源

C++:最强大的.NET语言之内存与资源

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

当运行环境中包含垃圾回收机制时,区别开内存管理和资源管理,就非常重要了。

作者:谢启东编译 来源:天极开发 2007年11月15日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
托管C++也与此类似,看起来像析构函数的代码其实是一个Finalize方法,编译器实际上插入了一个try-finally块并调用基类的Finalize方法,因此,C#与托管C++相对容易编写一个Finalize方法,但在编写Dispose方法时,却没有提供任何帮助。程序员们经常使用Dispose方法,把它当作一个伪析构函数以便在代码块末执行一点其他的代码,而不是为了释放任何资源。

  C++/CLI认识到了Dispose方法的重要性,并在引用类型中,使之成为一个逻辑"析构函数"。

ref class Derived : Base
{
 ~Derived() //实现或重载IDisposable::Dispose方法
 {
  //释放托管与非托管资源
 }

 !Derived() //实现或重载IDisposable::Dispose方法
 {
  //只释放非托管资源
 }
};

  对C++程序员来说,这让人感觉更自然了,能像以往那样,在析构函数中释放资源了。编译器会生成必要的IL(中间语言)来正确实现IDisposable::Dispose方法,包括抑制垃圾回收器调用对象的任何Finalize方法。事实上,在C++/CLI中,显式地实现Dispose方法是不合法的,而从IDisposable继承只会导致一个编译错误。当然,一旦类型通过编译,所有使用该类型的CLI语言,将只会看到Dispose模式以其每种语言最自然的方式得以实现。在C#中,可以直接调用Dispose方法,或使用一个using语句--如果类型定义在C#中。那么C++呢?难道要对堆中的对象正常地调用析构函数?此处当然是使用delete操作符了,对一个句柄使用delete操作符将会调用此对象的Dispose方法,而回收对象的内存是垃圾回收器该做的事,我们不需要关心释放那部分内存,只要释放对象的资源就行了。

Derived^ d = gcnew Derived();
d->SomeMethod()
delete d;

  如果表达式中传递给delete操作符的是一个句柄,将会调用对象的Dispose方法,如果此时再没有其他对象链接到引用类型,垃圾回收器就会释放对象所占用的内存。如果表达式中是一个本地C++对象,在释放内存之前,还会调用对象的析构函数。

  毫无疑问,在对象生命期管理上,我们越来越接近自然的C++语法,但要时刻记住使用delete操作符,却不是件易事。C++/CLI允许对引用类型使用堆栈语义,这意味着你能用在堆栈上分配对象的语法来使用一个引用类型,编译器会提供给你所期望的C++语义,而在底层,实际上仍是在托管堆中分配对象,以满足CLR的需要。

Derived d;
d.SomeMethod();

  当d超出范围时,它的Dispose将会被调用,以释放它所占用的资源。再则,因为对象实际是在托管堆中分配的,所以垃圾回收器会在它的生命期结束时释放它。来看一个ADO.NET的例子,它与C++/CLI中的概念非常相似。

SqlConnection connection("Database=master; Integrated Security=sspi");

SqlCommand^ command = connection.CreateCommand();
command->CommandText = "sp_databases";
command->CommandType = CommandType::StoredProcedure;

connection.Open();

SqlDataReader reader(command->ExecuteReader());

while (reader.Read())
{
 Console::WriteLine(reader.GetString(0));
}

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章