当前位置:天才代写 > tutorial > C语言/C++ 教程 > C++中克制异常信息通报到析构函数外

C++中克制异常信息通报到析构函数外

2017-11-06 08:00 星期一 所属: C语言/C++ 教程 浏览:639

在有两种环境下会挪用析构函数。第一种是在正常环境下删除一个工具,譬喻工具超出了浸染域或被显式地delete。第二种是异常通报的仓库辗转开解(stack-unwinding)进程中,由异常处理惩罚系统删除一个工具。

在上述两种环境下,挪用析构函数时异常大概处于激活状态也大概没有处于激活状态。遗憾的是没有步伐在析构函数内部区分出这两种环境。因此在写析构函数时你必需守旧地假设有异常被激活,因为假如在一个异常被激活的同时,析构函数也抛出异常,并导致措施节制权转移到析构函数外,C++将挪用terminate函数。这个函数的浸染正如其名字所暗示的:它终止你措施的运行,并且是当即终止,甚至连局部工具都没有被释放。

下面举一个例子,一个Session类用来跟踪在线计较机的sessions,session就是运行在从你一登录计较机开始一直到注销出系统为止的这段期间的某种对象。每个Session工具存眷的是它成立与释放的日期与时间:

class Session {
public:
 Session();
 ~Session();
 ...
private:
 static void logCreation(Session *objAddr);
 static void logDestruction(Session *objAddr);
};

函数logCreation 和 logDestruction被别离用于记录工具的成立与释放。我们因此可以这样编写Session的析构函数:

Session::~Session()
{
 logDestruction(this);
}

一切看上去很好,可是假如logDestruction抛出一个异常,会产生什么事呢?异常没有被Session的析构函数捕捉住,所以它被通报到析构函数的挪用者哪里。可是假如析构函数自己的挪用就是源自于某些其它异常的抛出,那么terminate函数将被自动挪用,彻底终止你的措施。这不是你所但愿产生的工作。措施没有记录下释放工具的信息,这是不幸的,甚至是一个大贫苦。那么事态果然严重到了必需终止措施运行的境地了么?假如没有,你必需防备在logDestruction内抛出的异常通报到Session析构函数的外面。独一的要领是用try和catch blocks。一种很自然的做法会这样编写函数:

Session::~Session()
{
 try {
  logDestruction(this);
 }
 catch (...) {
  cerr << "Unable to log destruction of Session object "
   << "at address "
   << this
   << ".\n";
 }
}

可是这样做并不比你本来的代码安详。假如在catch中挪用operator<<时导致一个异常被抛出,我们就又碰着了老问题,一个异常被转递到Session析构函数的外面。

我们可以在catch中放入try,可是这总得有一个限度,不然会陷入轮回。因此我们在释放Session时必需忽略掉所有它抛出的异常:

Session::~Session()
{
 try {
  logDestruction(this);
 }
 catch (...) { }
}

catch外貌上仿佛没有做任何工作,这是一个假象,实际上它阻止了任何从logDestruction抛出的异常被通报到session析构函数的外面。我们此刻能安枕无忧了,无论session工具是不是在仓库辗转开解(stack unwinding)中被释放,terminate函数都不会被挪用。

不答允异常通报到析构函数外面尚有第二个原因。假如一个异常被析构函数抛出而没有在函数内部捕捉住,那么析构函数就不会完全运行(它会停在抛出异常的谁人处所上)。假如析构函数不完全运行,它就无法完成但愿它做的所有工作。譬喻,我们对session类做一个修改,在成立session时启动一个数据库事务(database transaction),终止session时竣事这个事务:

Session::Session() // 为了简朴起见,,
{ // 这个结构函数没有
 // 处理惩罚异常
 logCreation(this);
 startTransaction(); // 启动 database transaction
}
Session::~Session()
{
 logDestruction(this);
 endTransaction(); // 竣事database transaction
}

假如在这里logDestruction抛出一个异常,在session结构函数内启动的transaction就没有被终止。我们也许可以或许通过从头调解session析构函数内的函数挪用顺序来消除问题,可是假如endTransaction也抛出一个异常,我们除了回到利用try和catch外,别无选择。

综上所述,我们知道克制异常通报到析构函数外有两个原因,第一可以或许在异常转递的仓库辗转开解(stack-unwinding)的进程中,防备terminate被挪用。第二它能辅佐确保析构函数总能完成我们但愿它做的所有工作。(假如你仍旧不很信服我所说的来由,可以去看Herb Sutter的文章Exception-Safe Generic Containers ,出格是“Destructors That Throw and Why They’re Evil”这段)。

 

    关键字:

天才代写-代写联系方式