More Exceptional C++中文版试读(异常安全议题及技术)

[Herb Sutter 的名作 More Exceptional C++ 中文版即将出版。作为本书译者,我很高兴将本书推荐给大家。征得华中科技大学出版社同意,我将公开部分译稿,敬请大家批评指正。

  

 

异常安全议题及技术

 

 

 

在现代C++程序设计中,对异常安全(exception safety)议题一无所知却想写出健壮的代码,这无异于痴人说梦。的确如此。

 

如果你在使用C++标准库,哪怕只是用到了new,你也得为异常做好准备。本章建立在Exceptional C++相应章节的基础上,并讨论了新的议题及相关技术,例如:std::uncaught_exception()是什么?它能帮助你写出更健壮的代码吗?异常安全影响到类的设计吗?或者,它可以只是作为事后的改进手段来使用吗?为什么要用管理者对象(manager objects)来封装资源所有权?为什么“资源获取才是初始化”的认识对于编写安全代码如此重要?

 

但首先还是让我们来热身一下,看一个有关异常安全的基本话题;这个话题对以下非常重要的C++基本概念进行了说明,并剖析了其更深层的含义:构造具有什么含义?什么是对象的生命期?

 

 

条款17:构造函数失败,之一:

对象生命期

 

难度:4

确切地说,构造函数产生异常时到底会发生些什么?如果异常来自子对象或成员对象的构造期间,情况又会怎样?

 

1. 请看下面这个类:

 

    // 17-1

    //

    class C : private A

    {

      B b_;

    };


C的构造函数中,如何捕捉从基类子对象(例如A)或成员对象(例如b_)的构造函数中抛出的异常?

 

2. 请看下面的代码:

 

    // 17-2

    //

    {

      Parrot p;

    }

 

这个对象的生命期何时开始?何时结束?在对象的生命期之外,对象处于什么状态?最后,如果它的构造函数抛出了一个异常,那将意味着什么?

 

解答

 

C++中增加function try block这一特性后,函数可以捕获异常的范围稍微增大了一些。本条款的内容涉及:

 

·在C++中,对象构造与构造失败的含义;

·基类或成员子对象的构造函数抛出异常时,function try block可用于转化(而非抑制)这个异常。

 

方便起见,除非特别指出,本条款中的“成员”指的是“非静态的类数据成员”。

 

Function Try Block

1. 请看下面这个类:

 

    // 17-1

    //

    class C : private A

    {

      B b_;

    };

 

C的构造函数中,如何捕捉从基类子对象(例如A)或成员对象(例如b_)的构造函数中抛出的异常?

 

这正是function try block的用武之地:

 

    // 17-1(a): 构造函数的function try block

    //

C::C()


try

      : A ( /*...*/ ) // 可选的初始化列表

      , b_( /*...*/ )

    {

    }

    catch( ... )

    {

      // 一旦A::A()B::B()抛出异常,我们会来到这儿

 

      // 如果A::A()成功,然后B::B()抛出异常,

      // C++语言将保证,在到达本catch block

      // 之前,A::~A()会被调用,以摧毁已经创建

      // 的基类A子对象。

    }

 

然而,更有趣的问题是:你为什么会想到这么做?这个问题引出了本条款两大要点的第一个。

 

对象生命期与构造函数异常的含义

过一会儿,我们将回答一个问题,即,上面C的构造函数是否可以(或应该)吸收(absorbAB的构造函数产生的异常,从而完全不发出异常。在可以正确回答这个问题之前,我们需要完全了解对象生命期1的概念,以及构造函数抛出异常的含义。

 

2. 请看下面的代码:

 

    // 17-2

    //

    {

      Parrot p;

    }

 

这个对象的生命期何时开始?何时结束?在对象的生命期之外,对象处于什么状态?最后,如果它的构造函数抛出了一个异常,那将意味着什么?

 

让我们一次回答一个问题:

 

问:一个对象的生命期何时开始?

答:当它的构造函数成功执行完毕并正常返回之时。也就是说,当控制(control)抵达构造函数体的末尾之时,或执行完一个更早的return语句之时。

 

问:一个对象的生命期何时结束?

__________________

1. 为简化起见,我在这里所说的只是类型为class、具有构造函数的对象的生命期。


答:当它的析构函数开始执行之时。也就是说,当控制抵达析构函数体的开始处之时。

 

问:对象的生命期结束之后,对象处于什么状态?

答:我们的回答正如一位知名软件大师曾经表述的那样:在谈到一段类似的代码时,他将局部对象(local object)拟人化地称为“他”:

 

    // 17-3

    //

    {

      Parrot& perch = Parrot();

    }

    // <-- 独白从这里开始

 

他并非日渐消瘦!他已经逝去!这只鹦鹉(Parrot)已经芳踪不再!他已经停止了生命!他已经死亡,去见他的造物者去了!他是死尸!被剥夺了生命,安静长眠!如果你没有把他放在枝头(perch),它已经命归黄土![甚至更早,在这个代码块尾部之前]他的代谢过程已经作古!他离开了枝头!他已经撒手人寰,摆脱了尘世的烦恼,拉上了生命的帷幕,加入了唱师班,无影无踪!这是一只前世的鹦鹉(ex-Parrot)!

 

——Dr. M.Python, B.Math, MA.Sc., Ph.D. (CompSci)2

 

撇开玩笑不说,此处的重点在于:在生命期开始之前与生命期结束之后,对象的状态完全一样——没有对象存在。就是这样。这一结论将我们带到第二个重要问题前:

 

问:从构造函数中抛出异常意味着什么?

答:这意味着构造已经失败,对象从没存在过,它的生命期从没开始过。确实,报告构造失败——也就是说,无法正确构造出某种类型的有效对象——的唯一方法是抛出一个异常。(是的,有一条如今已经过时的编程规则是这么说的:“如果程序出了问题,可以将一个状态标志设为‘bad’,让调用者通过一个IsOK()函数去检查它”;后面,我会对此谈谈我的看法。)

 

顺便说一句,如果构造函数不成功,析构函数就永远不会被调用,其原因正在于此——没有东西可以摧毁。它无法死亡,因为它从来就未曾生存过。请注意,这样一来,“一个对象的构造函数抛出异常”这句话实际上具有矛盾性。这样一种东西甚至不能被称为一个前对象(ex-object)。它从没有生存过,从没有加入过对象家族。它是一个非对象(non-object)。

 

__________________

2. Monty Python致歉。


对于C++的构造函数模型,我们可以总结如下:

只会是二者之一:

 

a) 构造函数正常返回,即,控制抵达函数体的尾部,或者执行了一个return语句。这种情况下,对象真实存在。

b) 构造函数抛出异常后退出。这种情况下,对象不仅不会继续存在,而且,实际上它根本就从未作为一个对象存在过。

 

没有其它的可能性。具备了这些知识,我们就可以更好地应对下一条款中的问题了:可否吸收异常?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: exceptional c指的是超乎寻常的C语言,即在使用C语言进行编程时,达到了非凡的水平和能力。这包括但不限于熟练掌握C语言的语法和特性,理解C语言的底层机制和内存管理,编写高效且可靠的代码,解决复杂而困难的问题。拥有exceptional c能力的程序员通常能够编写高性能的程序,优化代码,改善资源利用效率,提高软件的质量和可维护性。 而more exceptional c则进一步指的是在exceptional c的基础上,更进一步的提升和发展。它可能包括对C语言更深层次的理解,对C语言编程范式、设计模式和最佳实践的掌握,能够设计和实现复杂的数据结构和算法,以及利用C语言的扩展功能和库实现创新的解决方案。 与exceptional c相比,more exceptional c更注重在C语言的高级特性上的应用,如面向对象的编程,泛型编程,元编程等。通过更深入的学习和研究,更出色的C程序员可以利用这些高级技术,进一步提高代码的可读性,可维护性和重用性。 总而言之,exceptional c是对熟练掌握C语言编程的基本要求,而more exceptional c则代表在此基础上进一步提升和发展,拥有更高级的技能和能力。 ### 回答2: exceptional c是指非常优秀的C语言代码,具有出色的设计和实现,能够在效率、可靠性和可读性等方面表现出色。这种代码通常具有良好的算法和数据结构选择,以及正确的错误处理机制。 而more exceptional c是指比exceptional c更加出色的C语言代码,更具有创新和突破性。它可能包含了前沿的编程技术、高级的数据结构和算法,以及更为复杂和深入的问题解决方案。这种代码可能会利用C语言的底层优势,充分发挥计算机性能并提供更高的效率。 在开发过程中,编写exceptional c代码需要遵循良好的编程习惯和规范,保持代码的可维护性和可扩展性。这种代码通常具有清晰的结构和注释,函数和变量命名规范恰当。同时,编写exceptional c代码也要注意错误处理和异常处理,确保代码的健壮性和可靠性。 而more exceptional c则需要更深入的编程知识和技巧。它可能涉及更多的底层编程,例如操作系统级别的代码或者底层硬件的访问。同时,more exceptional c还可能包含更复杂的算法和数据结构,以及高级的设计模式和架构思想。编写more exceptional c代码需要对C语言的特性和底层工作原理有深刻的理解和掌握。 总之,exceptional c和more exceptional c都是指在C语言中表现出色的代码,但more exceptional c更进一步,采用更高级的技术和解决方案,展现出更出色的能力和创新精神。 ### 回答3: exceptional c是指非常出色的c,可能是指一个人的能力或者品质在某个方面超越了常人,表现出非凡的才华或者特点。它强调了c的某种特别之处,使得它在众多同类中脱颖而出。 而more exceptional c则意味着更加出色的c,即在exceptional c的基础上进一步提升,突破了先前的界限,表现出更加突出的表现和才能。它可以指一个人在原有的基础上通过努力和不断学习进步,取得了更加卓越的成就,或者是指一个事物在原有的基础上通过创新和改进,达到了更高的水平。 总之,exceptional c和more exceptional c都表达了某种非凡和出色的意思,但more exceptional c更加强调在原有的基础上取得更高的成就和突破。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值