动态分配资源的自动释放 – auto_ptr的实现原理 .

转载 2012年03月28日 14:57:48

动态分配资源的自动释放的英文是 Resource Allocation In Initialization,通常缩写成RAII。

根据《C++ Primer》第4版:

During stack unwinding, the function containing the throw, and possibly other functions in the call chain, are exited prematurely. In general, these functions will have created local objects that ordinarily would be destroyed when the function exited. When a function is exited due to an exception, the compiler guarantees that the local objects are properly destroyed. As each function exits, its local storage is freed. … If the local object is of class type, the destructor for this object is called automatically. As usual, the compiler does not work to destroy an object of built-in type.

假定有一个类定义如下:

// 资源类

class Student

{

public:

         Student(const string name = "Andrew", string gender = "M", int age = 6)

         {

                   this->name = name;

                   this->gender = gender;

                   this->age = age;

         }

 

         void printStudentInfo()

         {

                   cout << "Name: " << name << " ";

                   cout << "Gender: " << gender << " ";

                   cout << "Age: " << age << endl;

                   //throw runtime_error("Throw an exception deliberately...");                          // (1)

         }

 

         ~Student()

         {

                   // 下面这条语句用来提示资源是否被释放了

                   cout << "The destructor of class Student is called" << endl;

         }

 

private:

         string name;

         string gender;

         int age;

};

那么类似下面代码中的方式使用Student这个类,就会造成内存泄漏:

// 测试代码

int main()

{

         Student *stu = new Student("Andrew", "M", 6);

         stu->printStudentInfo();

 

         return 0;

}

因为在return之前,没有delete掉stu这个动态分配而来的资源(如果仅仅是这个程序,也没有内存泄漏之忧,因为整个应用都结束运行了,在此只是为了方便说明类似的使用方式是不可以的,即用了new动态分配了资源,而没有对应的delete去回收)。为了防止这样的方式造成的内存泄漏,上面的测试代码应该增加一行delete stu:

// 测试代码

int main()

{

         Student *stu = new Student("Andrew", "M", 6);                               // (2)

         stu->printStudentInfo();

delete stu;                                                                                            // (3)

 

         return 0;

}

这样就不会造成内存泄漏了。运行该应用,输出的结果是:

Name: Andrew Gender: M Age: 6

The destructor of class Student is called

输出的The destructor of class Student is called表明了Student类的析构函数得到了调用。

 

现在,如果在(2)和(3)中间发生了异常,即将Student类中的(1)语句uncomment掉,就会出现下面这样的错误提示:

This application has requested the Runtime to terminate it in an unusual way. Please contact the application’s support team for more information.

 

这样一来语句(3)即delete stu;就不会得到执行,因此也会造成内存泄漏。为了消除上面的错误,我们在前面的测试代码中,增加try-ctach来捕获异常,代码如下:

// 测试代码

int main()

{

         Student *stu = new Student("Andrew", "M", 6);                              // (2)

         try

         {

                   stu->printStudentInfo();                                                            

         }

         catch(const exception &e)

         {

                   cout << e.what() << endl;

         }

         delete stu;                                                                                                      // (3)

 

         return 0;

}

 

输出结果:

Name: Andrew Gender: M Age: 6

Throw an exception deliberately…

The destructor of class Student is called

 

这就说明,如果增加了try-catch,后面的delete stu;就会将用new动态分配的资源正确的予以释放。

 

进一步地,如果在stu->printStudentInfo();中出现了异常,而且后面也没有delete stu;这样的语句,用new分配给stu的资源进行自动释放?办法是有的。为此,我们需要增加一个类,定义如下:

// 资源管理类

template<typename T>

class Resource

{

public:

         Resource(T* p)

         {

                   // 将新分配的到的资源的地址赋给res,现在res指向了新分配到的资源

                   res = p;

         }

 

         ~Resource()

         {

                   if(res)

                   {

                            // 如果res指向的地址中,资源还没有被释放,那么则释放之

                            delete res;

                            res = 0;

                            cout << "Resources are deallocated here." << endl;

                   }

         }

private:

         T *res;

};

 

把测试代码改为:

// 测试代码

int main()

{

         Student *stu = new Student("Andrew", "M", 6);                     // (2)

         // 将stu绑定到Resource<Student>类型的res变量,res是一个local对象,当程序超出其可见范围时

         // 其析构函数会自动执行。而它的析构函数中,又会自动释放stu所指向的资源

         Resource<Student> res(stu);

         try

         {

                   stu->printStudentInfo();                                                            

         }

         catch(const runtime_error &e)

         {

                   cout << e.what() << endl;

         }

 

         return 0;

}

 

上面代码的运行结果:

Name: Andrew Gender: M Age: 6

Throw an exception deliberately…

The destructor of class Student is called

Resources are de-allocated here.

 

这说明即使没有delete stu;程序也正确地析构了相关动态非配的资源,从而实现了动态分配资源的自动释放。

 

在上面的代码中,我们用stu->printStudentInfo();来调用相关的函数,如果想用res直接调用,则需要重载Resource类的->操作符,代码如下:

// 资源管理类

template<typename T>

class Resource

{

public:

         Resource(T* p)

         {

                   // 将新分配的到的资源的地址赋给res,现在res指向了新分配到的资源

                   res = p;

         }

 

         ~Resource()

         {

                   if(res)

                   {

                            // 如果res指向的地址中,资源还没有被释放,那么则释放之

                            delete res;

                            res = 0;

                            cout << "Resources are deallocated here." << endl;

                   }

         }

 

         T* operator->() const

         {

                   if(res)

                            return res;

                   else

                            cout << "The underlying object is empty." << endl;

         }

 

private:

         T *res;

};

粗体字部分重载了->操作符,用来返回该类中的私有成员变量res。

 

相应的,测试代码做如下修改:

// 测试代码

int main()

{

         Student *stu = new Student("Andrew", "M", 6);                     // (2)

         // 将stu绑定到Resource<Student>类型的res变量,res是一个local对象,当程序超出其可见范围时

         // 其析构函数会自动执行。而它的析构函数中,又会自动释放stu所指向的资源

         Resource<Student> res(stu);

         try

         {

                   //stu->printStudentInfo();            // 这行被注释掉

                   res->printStudentInfo();            // 改用res来调用printStudentInfo

         }

         catch(const runtime_error &e)

         {

                   cout << e.what() << endl;

         }

 

         return 0;

}

运行结果和前面是一致的,也实现了动态分配资源的自动释放。事实上,这就是大名鼎鼎的auto_ptr的实现原理。

 

注意,代码开始处需要包含以下语句:

#include <iostream>

#include <string>

#include <stdexcept>                 // 处理异常时,必须包含此头文件

using namespace std;

 

轉自:http://blog.csdn.net/qq276592716/article/details/6698375

相关文章推荐

动态分配资源的自动释放 – auto_ptr的实现原理

动态分配资源的自动释放的英文是 Resource Allocation In Initialization,通常缩写成RAII。 根据《C++ Primer》第4版: “ During stac...

kubernetes 1.5安装 jenkins 带动态分配资源

kubernetes 1.5安装 jenkins 配置kubernetes1.5 jenkins,自动创建节点,使用完后自动注销节点的配置方法。 最后包括NFS的配置。 1. 配置要求    在k...
  • wenwst
  • wenwst
  • 2017年01月04日 09:18
  • 2693

智能指针(一):STL auto_ptr实现原理

文章转自:http://blog.csdn.net/weiwenhp/article/details/8706864 版权归原作者!智能指针实际上是一个类(class),里面封装了一个指针.它的用处...

智能指针(上)-----动态管理内存问题,auto_ptr的模拟实现

今天我们来详解C++中一个重要的知识点——智能指针。文章主要以下面几点来展开: 智能指针定义及动态内存的管理 智能指针作用 auto_ptr的模拟实现 智能指针定义 智能指针简单理解就是智能的指针,...
  • Pg_dog
  • Pg_dog
  • 2017年04月13日 09:22
  • 586

智能指针(一):STL auto_ptr实现原理

智能指针实际上是一个类(class),里面封装了一个指针.它的用处是啥呢? 指针与内存 说到指针自然涉及到内存.我们如果是在堆栈(stack)中分配了内存,用完后由系统去负责释放.如果是自定义类型,...

自动指针auto_ptr

  • 2013年02月25日 10:18
  • 59KB
  • 下载

STL 源码研读笔记(1)– auto_ptr

本文作者:campos 本文出处:http://www.mykernelspace.com  (转载请保留此行,谢谢)       很久没上来写东西了,最近认真学习了一下C++,发现真是博大精深...

从零开始学C++之对象语义与值语义、资源管理(RAII、资源所有权)、模拟实现auto_ptr<class>、实现Ptr_vector

一、对象语义与值语义 1、值语义是指对象的拷贝与原对象无关。拷贝之后就与原对象脱离关系,彼此独立互不影响。比如说int,C++中的内置类型都是值语义,前面学过的三个标准库类型string,vector...

以对象管理资源——C++智能指针auto_ptr简介

auto_ptr是C++标准库提供的类模板,它可以帮助程序员自动管理用new表达式动态分配的单个对象。auto_ptr对象被初始化为指向由new表达式创建的对象,当auto_ptr对象的生命期结束时,...
  • lihao21
  • lihao21
  • 2013年09月01日 21:05
  • 1302

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析,左值与右值

C++:浅谈c++资源管理以及对[STL]智能指针auto_ptr源码分析标签:STL 智能指针 auto_ptr 源码分析by 小威威// 2016.05.01 对第三部分源码分析中的复制构造函...
  • linwh8
  • linwh8
  • 2016年04月28日 00:31
  • 3852
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:动态分配资源的自动释放 – auto_ptr的实现原理 .
举报原因:
原因补充:

(最多只允许输入30个字)