📄 item_072.htm
字号:
@list l2:level5
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:180.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:"Courier New";}
@list l2:level6
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:216.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:Wingdings;}
@list l2:level7
{mso-level-number-format:bullet;
mso-level-text:\F0B7;
mso-level-tab-stop:252.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:Symbol;}
@list l2:level8
{mso-level-number-format:bullet;
mso-level-text:o;
mso-level-tab-stop:288.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:"Courier New";}
@list l2:level9
{mso-level-number-format:bullet;
mso-level-text:\F0A7;
mso-level-tab-stop:324.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
font-family:Wingdings;}
ol
{margin-bottom:0cm;}
ul
{margin-bottom:0cm;}
-->
</style>
<!--[if gte mso 10]>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
</style>
<![endif]--><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="2050"/>
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1"/>
</o:shapelayout></xml><![endif]-->
</head>
<body lang=ZH-CN style='tab-interval:36.0pt'>
<div class=Section1>
<h3><span lang=EN-US>72. </span><span style='font-family:宋体;mso-ascii-font-family:
Arial;mso-hansi-font-family:Arial'>尽量用异常来报告错误</span></h3>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>摘要</span></b></p>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>受到伤害时,要(用异常来)抵制:与错误码相比,要尽量用异常来报告错误。对一些无法使用异常的错误(参见第</span><span
lang=EN-US>62</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>条),或者一些不属于错误的情况,可以用状态码(</span><span
lang=EN-US>status code</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>,例如:返回码,</span><span
class=SpellE><span lang=EN-US>errno</span></span><span style='font-family:宋体;
mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>)来报告。如果不可能或不需要从错误中恢复,那么可以使用其它方法,比如正常或非正常地终止程序。</span></p>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<p class=MsoNormal><b style='mso-bidi-font-weight:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>讨论</span></b></p>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>在过去</span><span lang=EN-US>20</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>年产生的现代编程语言中,大多数都使用异常作为主要的错误报告机制,这并不是一个巧合。正如它的定义,异常是用来报告正常处理过程的例外情况,也称为“错误”,它在第</span><span
lang=EN-US>70</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>条中被定义为对前置条例,后置条件和不变性的违反。正如所有的错误报告机制,异常不应该出自正常的,成功的操作。</span></p>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<p class=MsoNormal><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>我们用术语“状态码”来涵盖通过编码来报告状态(包括返回码,</span><span
class=SpellE><span lang=EN-US>errno</span></span><span style='font-family:宋体;
mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>,</span><span
class=SpellE><span lang=EN-US>GetLastError</span></span><span style='font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>函数,以及其它用来返回或取得编码的策略)的所有形式,用“错误码”特指用来报告错误的状态码。在</span><span
lang=EN-US>C++</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>中,和用错误码来报告错误相比,用异常来报告错误具有许多明显的优势,所有这些都使得你的代码更健壮:</span></p>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<ul style='margin-top:0cm' type=disc>
<li class=MsoNormal style='mso-list:l1 level1 lfo1;tab-stops:list 36.0pt'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>程序员不能无视异常:错误码的最糟糕的缺点就是在默认情况下它们会被忽略;即使是给予错误码微不足道的关注,都必须显示地编写代码,以接受错误并做出反应。程序员因为偶然(或因为懒惰)而忘记关注错误码是很平常的事。这使得代码复查变得更困难。程序员不能无视异常;要忽略异常,必须显式地捕获它(即使只是用</span><span
lang=EN-US>catch(...)</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>),然后不对之进行处理。</span></li>
</ul>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<ul style='margin-top:0cm' type=disc>
<li class=MsoNormal style='mso-list:l1 level1 lfo1;tab-stops:list 36.0pt'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>异常会自动传递:默认情况下错误码不会跨作用域传递;为了把一个低层的错误码通知高层的调用函数,程序员必须在在中间层的代码中显式地手工编写代码以传递该错误。异常会自动地跨作用域传递,直到被处理为止。(“试图使每个函数都成为防火墙并不是什么好主意。”</span><span
lang=EN-US>[Stroustrup94, §16.8] </span><span style='font-family:宋体;
mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>)</span></li>
</ul>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<ul style='margin-top:0cm' type=disc>
<li class=MsoNormal style='mso-list:l1 level1 lfo1;tab-stops:list 36.0pt'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>异常处理从主控制流中去除了错误处理及恢复:错误码的检测及处理,一旦要写的话,就必须夹杂在主控制流中(并使之变得难以理解)。这使得主控制流以及错误处理的代码都更难以理解和维护。异常处理很自然地把错误检测及恢复移到醒目的</span><span
lang=EN-US>catch</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>代码块中,换句话说,它使错误处理既醒目,又易于使用,而不是像意大利面条那样纠缠在主控制流中。</span></li>
</ul>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<ul style='margin-top:0cm' type=disc>
<li class=MsoNormal style='mso-list:l1 level1 lfo1;tab-stops:list 36.0pt'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>对从构造函数和操作符中报告错误来说,异常处理比其它选择要好:复制构造函数和操作符都有预定义的签名(</span><span
lang=EN-US>signature</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>),它们没有给返回值留下余地。特别是,构造函数根本就没有返回类型(连</span><span
lang=EN-US>void</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>都不是),又比如每个</span><span
lang=EN-US>operator+</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>必须有两个参数,并返回一个对象(以某个规定的类型;参见第</span><span
lang=EN-US>26</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>条)。对操作符来说,虽然使用错误码并不能令人满意,但至少还是可行的;这需要类似</span><span
class=SpellE><span lang=EN-US>errno</span></span><span style='font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>的方法,或者更差的方法,比如将状态信息与对象包在一起。对构造函数来说,用错误码是不可行的,因为</span><span
lang=EN-US>C++</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>语言把构造函数异常和构造函数失败紧紧地绑定在了一起,因此这两者无疑是同义词;如果我们想用类似</span><span
class=SpellE><span lang=EN-US>errno</span></span><span style='font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>的方法取而代之,比如:</span></li>
</ul>
<p class=MsoNormal style='margin-left:18.0pt'><span lang=EN-US><o:p> </o:p></span></p>
<p class=MsoNormal style='margin-left:54.0pt;text-indent:18.0pt;tab-stops:288.0pt'><span
class=SpellE><span lang=EN-US>SomeType</span></span><span lang=EN-US> <span
class=SpellE>anObject</span>;<span style='mso-tab-count:1'> </span><i
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -