分享
 
 
 

C++ Gotchas 条款64:抛出String Literals

王朝c/c++·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Gotcha #64: Throwing String Literals

Gotcha条款64:抛出String Literals

许多C++编程教本的作者在展示异常机制时都抛出字符文字串(character string literals)信息:

throw "Stack underflow!";

他们知道这种实作手法本应回避,但是他们还是这样做了,因为那只是“教学性示例”。不幸的是,这样做示例就隐含了“模仿这个示例”的建议(译注:毕竟,读者当然会倾向于效仿所看教本中的示例来学习),而这些作者们通常忽视了还要提示读者:“真正照这样做的话,会招致刻意伤害和厄运”。

绝不要抛出string literals作为exception objects(异常对象)。从原理上讲,原因是:这些exception objects最终应该被捕获,而且应该是根据其型别(type)来捕获,而不是根据其值(value)来捕获:

try {

// . . .

}

catch( const char *msg ) {

string m( msg );

if( m == "stack underflow" ) // . . .

else if( m == "connection timeout" ) // . . .

else if( m == "security violation" ) // . . .

else throw;

}

抛出和捕获string literals所产生的实际影响是,经由exception object的型别,几乎没有包含任何有关异常的信息。这种不甚严密的做法要求“catch clause拦截每一个同类异常并通过检视其值(value)来判断是否合乎捕获条件”。更糟的是,对值的比较也是很不严密的;一旦该“错误消息”在大小写或格式方面有改变,这种比较就毫无效用了。如果在上面的例子中发生这种情况,我们就永远无法发觉“栈发生下溢(stack underflow)”的情况。

同样的情况也存在于其它预定义型别和标准型别的异常中。抛出integers,floating point numbers,strings,或者(在一个糟糕透顶的日子)float vector组成的sets,都会引发类似的问题。简单地说,“抛出预定义型别之异常对象”的问题在于:当我们捕获到一个此种异常时,我们无法知道它代表什么意思,从而也无法确定如何处理异常。抛出该异常的人好像在愚弄我们:“发生了非常非常糟糕的事情!你猜是什么?”而我们别无选择,只好玩起做作的猜谜游戏,并很可能会玩输。

所谓exception type(异常型别)是一个用来代表异常的抽象数据型别(abstract data type)。设计这些异常型别时所要遵循的原则无异于设计其它任何抽象数据型别:辨识并具名一个概念,为其定出抽象的操作集合并实现之。在实现过程中,要考虑初始化、拷贝以及型别转换等问题。很简单嘛。用string literal来表示一个异常,较之用complex number来表示一个异常,同样都是没有多大意义。从理论上讲这样做或许会凑效,但从实际上讲这会变得冗长乏味,臭虫百出。

当我们抛出“代表stack underflow()的异常”时,我们试图表达什么样的抽象概念呢?噢。可不就是它吗。

class StackUnderflow {};

通常,一个exception object的型别要能传达所有关于该异常的信息;而对于exception types来说,“经由显式声明的成员函数来进行信息发放(dispense)”也没什么不寻常的。然而,“提供描述性文本的能力”经常是信手拈来的。其它不太常需要的相关信息也可以记录到exception object当中:

class StackUnderflow {

public:

StackUnderflow( const char *msg = "stack underflow" );

virtual ~StackUnderflow();

virtual const char *what() const;

// . . .

};

如果提供了能返回描述性文本的函数,那么其应该是一个名为what的virtual member function,具有上述的表达形式。这样做是考虑到该异常与标准异常型别的正交性,因为标准异常型别都提供了这个函数。事实上,让自定义的异常型别派生自标准异常型别,通常是个好主意:

class StackUnderflow : public std::runtime_error {

public:

explicit StackUnderflow( const char *msg = "stack underflow" )

: std::runtime_error( msg ) {}

};

这就使我们可以将其作为StackUnderflow、较为一般化的runtime_error,或更具一般性的标准异常(runtime_error的public base class)来捕获。提供一个更一般化但非标准的exception type,通常也是个好主意。一般来说,这种型别被作为base class使用,特定模块或程序库可能抛出的所有exception types都派生自它:

class ContainerFault {

public:

virtual ~ContainerFault();

virtual const char *what() const = 0;

// . . .

};

class StackUnderflow

: public std::runtime_error, public ContainerFault {

public:

explicit StackUnderflow( const char *msg = "stack underflow" )

: std::runtime_error( msg ) {}

const char *what() const

{ return std::runtime_error::what(); }

};

最后要说的是,为exception types提供寻常的copy和destruction语义也是必需的。特别是,抛出一个异常就暗示着“copy construct该exception type对象必须是合法的”,因为这正是运行期异常机制在异常被抛出时要做的事情(详见Gotcha条款65),而当该异常被处理之后也必须销毁这个拷贝。通常可以让编译器为我们自动编写这些操作(详见Gotcha条款49):

class StackUnderflow

: public std::runtime_error, public ContainerFault {

public:

explicit StackUnderflow( const char *msg = "stack underflow" )

: std::runtime_error( msg ) {}

// StackUnderflow( const StackUnderflow & );

// StackUnderflow &operator =( const StackUnderflow & );

const char *what() const

{ return std::runtime_error::what(); }

};

现在,stack type的用户可以自行选择,让stack underflow作为不同层级的异常型别被捕获,其可以是StackUnderflow(用户知道自己在使用stack type,希望特别关注它)、较一般化的ContainerFault(用户知道自己在使用container library,希望捕获任何container 引发的错误)、runtime_error(用户不知道自己是否在使用哪个container library,希望处理任何标准运行期错误),或最一般化的exception(用户准备处理任何标准异常)。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有