构造函数应该尽量避免产生异常

来源:互联网 发布:淘宝低价交易风险通知 编辑:程序博客网 时间:2024/06/08 09:38


构造函数应该尽量避免产生异常

1.说明

       构造函数是对一个对象进行初始化,一般来说,构造函数不应该设计的太复杂,即只进行简单的成员变量的初始化即可,
这样就可以更好的保证构造函数不会产生异常。



2.构造函数产生异常的危害

    C++在进行实例化对象,当调用构造函数的过程中发生异常时,这将导致无法调用对象的析构函数,
    这时仅仅清理和释放产生异常前的那些C++管理的变量空间等,而我们动态申请的资源(通过析构函数释放)是无法自动释放的,这将会导致资源泄露。


3.解决构造函数出现的异常

如果你的构造函数,不仅仅是进行简单的成员变量的初始化,还需涉及到了一系列资源的分配,可以通过下述方法解决:

容易出现资源泄露代码如下:

class Test{public:    Test()    {/* pA = new A(), 注意了,这里针对的是动态分配资源,失败返回NULL,进行DELETE NULL不会出现异常,如果是其他资源,这里出现异常需要额外的处理,  即需要考虑资源失败和成功的不同处理方式,例如,对互斥器未加锁的情况下进行解锁,会导致未定义行为。*/        pA = new A();             ...             }    ~Test()    {                delete pA;...    }private:    A* pA;};






(1)、方法一:通过异常处理机制,一旦发生异常,先进行资源的释放

Test::Test(){           try        {            pA = new A();     //资源的异常,资源申请失败也就谈不上释放资源了,更主要考虑的是,申请资源成功后的下面的异常。            ...        }        catch (...)        {            if(NULL != pA)            {                  delete pA;            }            throw;  //抛出对应异常,交给上层处理        }   }





(2)、方法二:通过智能指针进行管理

class Test{public:    Test()    {        spA = std::make_shared<A>;  //资源由智能指针进行处理        ...    }    ~Test()    {            }private:    std::shared_ptr< A > spA;};




 

(3)、方法三:把资源申请和释放的操作存放在另外的Init()和Release()函数


class Test{public:    Test()    {        pA = NULL;        if (!Init()){                  Release();}...    }    ~Test()    {        Release();    } private:    bool Init()    {                            try            {         pA = new A();   //资源的异常,资源申请失败也就谈不上释放资源了,更主要考虑的是,申请资源成功后的下面的异常。                  ...            }            catch (...)            {                return false;            }        }        return true;    }     void Release()    {        if(NULL != pA)        {            delete pA;            pA = NULL;       }    }private:    A* pA;    };






总结:

(1)、构造函数中发生异常,会导致析构函数不能被调用,但对象本身已申请到的内存资源会被系统释放(已申请到资源的内部成员变量会被系统依次逆序调用其析构函数)。
(2)、由于析构函数不能被调用,这就可能会造成内存泄露或系统资源未被释放。

(3)、构造函数中如果发生异常,必须在构造函数抛出异常之前,把系统资源释放掉,以防止内存泄露。




0 0