【ThinkingInC++】69、异常处理

来源:互联网 发布:橘子说淘宝装修工具箱 编辑:程序博客网 时间:2024/05/05 19:17

第一章 异常处理

1.5清理

1.5.1 资源管理

如果一个对象的构造函数在执行过程中抛出异常,那么这个对象的析构函数就不会被调用。

Rawp.cpp

/*** 书本:【ThinkingInC++】* 功能:资源管理* 时间:2014年10月8日20:19:03* 作者:cutter_point*/#include <iostream>#include <cstddef>using namespace std;class Cat{public:    Cat() { cout<<"Cat()"<<endl; }    ~Cat() { cout<<"~Cat()"<<endl; }};class Dog{public:    void* operator new(size_t sz)    {        cout<<"分配一个Dog的空间"<<endl;        throw 47;   //抛出异常,后面为了检验构造函数抛出异常的后果    }    void operator delete(void* p)    {        cout<<"回收一个Dog的空间"<<endl;        ::operator delete(p);    }};class UseResources{    Cat* bp;    Dog* op;    //这个事类的组合public:    UseResources(int count=1)    {        cout<<"UseResource的构造函数"<<endl;        bp=new Cat[count];        op=new Dog;    }    ~UseResources()    {        cout<<"~UseResources的析构函数"<<endl;        delete [] bp;   //回收数组空间        delete op;    }};int main(){    try    {        UseResources ur(3);    }    catch(int)    {        cout<<"inside handler"<<endl;    }    return 0;}


 

 

1.5.2 使所有事物都成为对象

·在构造函数中捕获

·在对象的构造函数中分配资源,并且在对象的析构函数中释放资源。

Wrapped.cpp

/*** 书本:【ThinkingInC++】* 功能:使所有事物都成为对象,防止资源泄露* 时间:2014年10月8日20:19:38* 作者:cutter_point*/#include <iostream>#include <cstddef>using namespace std;template<class T, int sz=1>class PWrap{    T* ptr; //一个这个类型的指针public:    class RangeError {};    //这是一个异常类    PWrap()    {        ptr=new T[sz];  //构造函数,给数据成员创建初值        cout<<"PWrap的构造函数"<<endl;    }    ~PWrap()    {        delete [] ptr;  //析构        cout<<"PWrap的析构函数"<<endl;    }    T& operator [] (int i) throw(RangeError)    //抛出一个RangeError对象的异常    {       if(i >= 0 && i < sz) return ptr[i];       throw RangeError();  //超出范围就抛出异常    }};class Cat{public:    Cat() { cout<<"Cat()猫的构造函数"<<endl; }    ~Cat() { cout<<"~Cat()猫的析构函数"<<endl; }    void g() {}};class Dog{public:    void* operator new[](size_t)    {        cout<<"分配狗的空间"<<endl;        throw 47;   //内存不够抛出异常    }    void operator delete[](void* p)    {        cout<<"回收狗的内存空间"<<endl;        ::operator delete[](p);    }};class UseResources{    PWrap<Cat, 3> cats; //创建3只猫    PWrap<Dog> dog;public:    UseResources() { cout<<"UseResources构造函数"<<endl; }    ~UseResources() { cout<<"~UseResources析构函数"<<endl; }    void f() { cats[1].g(); }};int main(){    try    {        UseResources ur;    }    catch(int)    {        cout<<"抛出异常,捕获一个整形的数值"<<endl;    }    catch(...)    {        cout<<"其他的捕获(...)"<<endl;    }    return 0;}


 

 

 

 

1.5.3 auto_ptr

RAII:资源获得式初始化

1.7 异常规格说明

Unexcepted.cpp

/*** 书本:【ThinkingInC++】* 功能:关于设置自己的异常函数,来显示不可预知的异常* 时间:2014年10月8日20:20:06* 作者:cutter_point*/#include <exception>#include <iostream>#include <cstdlib>using namespace std;class Up {};class Fit {};void g();void f(int i) throw(Up, Fit)    //根据给的int值来抛出异常{    switch(i)    {    case 1: throw Up();    case 2: throw Fit();    }    g();    //本来在版本一的g()只是被声明的时候是不会抛出任何异常的,但是后面又抛出了一个int型的异常}//定义函数g()   所以这里违反了异常抛出的规格(只有两种)void g() { throw 47; }void my_unexcepted()    //这个用来设置在规格之外的异常抛出{    cout<<"规格之外的异常抛出,不是Up也不是Fit"<<endl;    exit(0);}int main(){    set_unexpected(my_unexcepted);    //设置规格之外的异常将会调用的函数,忽略返回值    for(int i=1 ; i <= 3 ; ++i)        try        {            f(i);        }        catch(Up)        {            cout<<"抛出Up类型的异常"<<endl;        }        catch(Fit)        {            cout<<"抛出Fit类型的异常"<<endl;        }    return 0;}


 

 

1.8 异常安全

对于赋值操作符。

1)确保程序不是给自己赋值。如果是的话,到步骤6

2)给指针数据成员分配所需的新内存

3)从原来的内存区间向新分配的内存区拷贝数据

4)释放原有的内存

5)更新对象的状态,也就是把指向分配新堆内存地址的指针赋值给指针数据成员

6)返回*this

 

关于句柄

从上面的定义中的我们可以看到,句柄是一个标识符,是拿来标识对象或者项目的,它就象我们的姓名一样,每个人都会有一个,不同的人的姓名不一样,但是,也可能有一个名字和你一样的人。从数据类型上来看它只是一个16位的无符号整数。

 

管理其他资源的类

 

Strlen

需要明确的第一点,strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符'/0'为止,然后返回计数器值。

 

SafeAssign.cpp

 

/*** 书本:【ThinkingInC++】* 功能:关于operator=的安全分配内存* 时间:2014年10月8日20:20:41* 作者:cutter_point*/#include <iostream>#include <new>  //为了抛出异常bad_alloc#include <cstring>#include <cstddef>using namespace std;class HasPointers{    //这里设置一个句柄类来管理我们的数据    struct MyData    {        const char* theString;        const int* theInts;        size_t numInts;        //构造函数        MyData(const char* pString, const int* pInts, size_t nInts) : theString(pString), theInts(pInts), numInts(nInts) {}    }*theData;  //这个指针是指向这个结构体的    //这里为了安全的分配内存,我们使用一个clone静态函数    static MyData* clone(const char* otherString, const int* otherInts, size_t nInts)    {        /*        需要明确的第一点,strlen所作的仅仅是一个计数器的工作,它从内存的某个位置(可以是字符串开头,        中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符'/0'为止,然后返回计数器值。        */        char* newChars=new char[strlen(otherString)+1]; //吧这个字符串的长度加一,作为这个数组的长度,最后一位是'/0'        int* newInts;        //这里分配int类型的,避免异常        try        {            newInts=new int[nInts];        }        catch(bad_alloc&)        {            delete []newChars;            throw;        }        try        {            strcpy(newChars, otherString);  //拷贝到newChars里面去            for(size_t i=0 ; i < nInts ; ++i)                newInts[i]=otherInts[i];    //吧otherInts里面的数据赋值给newInts        }        catch(...)        {            delete []newInts;            delete []newChars;            throw;        }        return new MyData(newChars, newInts, nInts);    }    //一个重载的clone,拷贝构造函数    static MyData* clone(const MyData* otherData)    {        return clone(otherData->theString, otherData->theInts, otherData->numInts);    }    //内存清理    static void cleanup(const MyData* theData)    {        //回收全部内存,只要使用了指针的,都要把指针指向的内存回收掉        delete theData->theString;        delete theData->theInts;        delete theData;    }public:    //构造函数    HasPointers(const char* someString, const int* someInts, size_t numInts)    {        theData=clone(someString, someInts, numInts);    }    //拷贝构造函数    HasPointers(const HasPointers& source) { theData=clone(source.theData); }    //赋值拷贝运算符    HasPointers& operator=(const HasPointers& rhs)    {        //避免自赋值        if(this != &rhs)        {            MyData* newData=clone(rhs.theData->theString, rhs.theData->theInts, rhs.theData->numInts);            cleanup(theData);            theData=newData;        }        return *this;    }    //析构函数    ~HasPointers() { cleanup(theData); }    //友元函数    friend ostream& operator<<(ostream& os, const HasPointers& obj)    {        os<<obj.theData->theString<<" : ";        for(size_t i=0 ; i < obj.theData->numInts ; ++i)            os<<obj.theData->theInts[i]<<' ';        return os;    }};int main(){    int someNums[]={1, 2, 3, 4};    size_t someCount=sizeof(someNums)/sizeof(someNums[0]);    int someMoreNums[]={5, 6, 7};    size_t someMoreCount=sizeof(someMoreNums)/sizeof(someMoreNums[0]);    cout<<"这两个数组长度是:"<<someCount<<" : "<<someMoreCount<<endl;    HasPointers h1("Hello", someNums, someCount);    HasPointers h2("Goodbye", someMoreNums, someMoreCount);    cout<<h1<<endl;    h1=h2;    cout<<h1<<endl;    return 0;}


 

 

0 0
原创粉丝点击