ITEEDU

13.15 auto_ptr类与动态内存分配

一个常见的编程习惯是在空闲存储区中动态分配内存(可能是对象),将该内存的地址赋给一个指针,使用这个指针操作内存,并在该内存不再需要时用delete释放内存。如果内存分配之后和执行delete语句之前发生异常,则可能发生内存泄漏。ANSI/ISO C++草案标准提供<memory>头文件中的auto_ptr类模板,可以解决这个问题。

auto_ptr类对象维护动态分配内存的指针。当auto_ptr对象超出范围时,对指针数据成员进行一个delete操作。auto_ptr类模板提供了+和- >运算符.因此auto_ptr对象可以像普通指针变量一样使用。图13.7演示auto_ptr对象指向Integer类对象(在第8行到第18行定义)。

// Fig. 13.7: fig13_07.cpp
 // Demonstrating auto_ptr
 #include <iostream>
 #include <memory>
 using namespace std;
 class Integer {
 public:
   Integer( int i = 0 ) : value( i )
     {cout << "Constructor for Integer " << value << endl; }
   ~Integer()
     {cout << "Destructor for Integer " << value << endl; }
   void setInteger( int i ) { value = i; }
   int getInteger() const { return value; }
 private:
   int value;
 };
 int main()
 {
   cout << "Creating an auto_ptr object that points "
       << "to an Integer\n";
   auto_ptr< Integer > ptrToInteger( new Integer( 7 ) );
   cout << "using the auto_ptr to manipulate the Integer\n";
   ptrToInteger->setInteger( 99 );
   cout << "Integer after setInteger: "
       << ( *ptrToInteger ).getInteger()
       << "\nTerminating program" << endl;
   return 0;
 }
输出结果:
Creating an auto_ptr object that points to an Integer
Constructor for Integer 7
Using the auto_ptr to manipulate the Integer
Integer after setInteger: 99
Terminating program
Destruct for Integer 99
图 13.7演示auto_ptr

第25行: auto_ptr<Integer> ptrToInteger(new Integer(7 ));

生成aut_ptr对象ptrToInteger并用动态分配Inleger对象的指针(包含数值7)初始化。

第28行:

ptrToInteger- >setInteger(99);

用auto_ptr重载->运算符和函数调用运算符()调用ptrToInteger所指Integer对象的setInteger函数。

第30行:

(*ptrToInteger).getInteger()

用auto_ptr重载*运算符复引用ptrToInteger,然后用圆点运算符和函数调用运算符()调用ptrTolmeger所指Integer对象的getInteger函数。

由于ptrToInteger是main中的局部自动变量,因此main终止时删除ptrToInteger。这样就强制删除ptrToInteger所指的Integer对象,从而强制调用Integer类的析构函数。更重要的是这个方法可以防止内存泄漏。

13.16 标准库异常层次

经验表明,异常是可以分类的。C++草案标准提供了标准库异常层次。这个层次以基类excephon开始(在头文件<exception>中定义),该基类提供服务what(),在每个派生类中重定义,发出相应的错误消息。

从基类exception可以派生直接派生类runtime_error和Iogic_error(都在头文件 <stdexcept>中定义),每个派生类又可以派生其他类。

从exception中还可以派生由于C++语言特性而抛出的异常,例如,new抛出bad_alloc(13.14节).dynamic_cast抛出bad_cast(第2l章),typeid抛出bad_typeid(第21章)。如果发生意外异常时,通过在函数的抛出表中加上std::bad_exeeption,unexpected()抛出bad_exception而不是(默认)终止程序或调用set_unexpected指定的另一函数。

logic_error类是几个标准异常类的基类,表示程序逻辑中的错误,可以通过编写正确的代码来防止。下面介绍其中的一些类。invalid_argument类表示向函数传入无效参数(可以通过编写正确的代码来防止)。length_error类表示长度大于所操作对象允许的最大长度(第19章处理string时会抛出length_error异常)。out_of_range类表示数组和string下标之粪的值超界。

runtime_error类是几个其他异常类的基类,表示程序中只能在执行时发现的错误。overflow_error类表示发生运算上溢错误;underflow_error类表示发生运算下溢错误。

软件工程视点13.12

标准exception层次只是一个起点.用户可“抛出标准异常、抛出从标准异常派生的异常或抛出不是从标准异常派生的异常。

常见编程错误13.14

用户自定义异常类不一定从exception类派生。 因此catch(exception并井不保证捕获程序可能遇到的各种异常。

测试与调试提示13. 3
要捕获try块可能抛出的所有异常,用catch(...)。