📄 item_014.htm
字号:
<div class=Section1 style='layout-grid:15.6pt'>
<h3><span lang=EN-US>14</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 style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>不要把原来可以在编译时做的事情推迟到运行的时候才做:代码最好写得能够让编译器在编译时检查程序的不变性(</span><span
lang=EN-US>invariant</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 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>
<ul style='margin-top:0cm' type=disc>
<li class=MsoNormal style='mso-list:l0 level1 lfo1;tab-stops:list 36.0pt'><i
style='mso-bidi-font-style:normal'><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>静态检查与数据和控制流无关:</span></i><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>静态检查能够保证与程序的输入及执行流程无关。相反,为了确信运行时检查足够可靠,必须用对所有输入都具有代表性的样本进行测试。除了一些没什么实用价值的系统,对所有系统而言,这是很无趣的任务。</span></li>
<li class=MsoNormal style='mso-list:l0 level1 lfo1;tab-stops:list 36.0pt'><i
style='mso-bidi-font-style:normal'><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>静态地表达的模型更强:</span></i><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
lang=EN-US>68</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>条)</span><i
style='mso-bidi-font-style:normal'><span lang=EN-US><o:p></o:p></span></i></li>
<li class=MsoNormal style='mso-list:l0 level1 lfo1;tab-stops:list 36.0pt'><i
style='mso-bidi-font-style:normal'><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>静态检查不会导致运行时开销:</span></i><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>用静态检查取代动态检查得到的可执行文件会运行得更快,同时也没有牺牲正确性。</span><i
style='mso-bidi-font-style:normal'><span lang=EN-US><o:p></o:p></span></i></li>
</ul>
<p class=MsoNormal><i style='mso-bidi-font-style:normal'><span lang=EN-US><o:p> </o:p></span></i></p>
<p class=MsoNormal><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
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 lang=EN-US>Java</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>,</span><span lang=EN-US>ML</span><span style='font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>,</span><span
lang=EN-US>Haskell</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>)还是动态地(</span><span
lang=EN-US>Smalltalk</span><span style='font-family:宋体;mso-ascii-font-family:
"Times New Roman";mso-hansi-font-family:"Times New Roman"'>,</span><span
lang=EN-US>Ruby</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>,</span><span lang=EN-US>Python</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>,</span><span lang=EN-US>Lisp</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 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
lang=EN-US>99</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>,</span><span lang=EN-US>100</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><span lang=EN-US>71</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 style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>有几种情况可以用编译时检查代替动态检查。</span></p>
<p class=MsoNormal><i style='mso-bidi-font-style:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>示例</span><span lang=EN-US>1</span></i><i style='mso-bidi-font-style:
normal'><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>:编译时布尔状态。</span></i><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>如果要对编译时的布尔状态做检测,如</span><span lang=EN-US>sizeof(int) >=
8,</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>那么可以用静态断言代替运行时的检测。(但同时请参见第</span><span
lang=EN-US>91</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><i style='mso-bidi-font-style:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>示例</span><span lang=EN-US>2</span></i><i style='mso-bidi-font-style:
normal'><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>:编译时多态。</span></i><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>在定义泛型函数或类型时请考虑用编译时多态(模板)代替运行时多态(虚函数)。前者将产生更适于静态检查的代码。(参见第</span><span
lang=EN-US>64</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><i style='mso-bidi-font-style:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>示例</span><span lang=EN-US>3</span></i><i style='mso-bidi-font-style:
normal'><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>:枚举。</span></i><span style='font-family:
宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:"Times New Roman"'>在需要表达符号常量或受限的整数值时请考虑使用<b
style='mso-bidi-font-weight:normal'>枚举</b>(或者,定义一个完整的类型也不错)。</span></p>
<p class=MsoNormal><span lang=EN-US><o:p> </o:p></span></p>
<p class=MsoNormal><i style='mso-bidi-font-style:normal'><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>示例</span><span lang=EN-US>4</span></i><i style='mso-bidi-font-style:
normal'><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>:向下转型。</span></i><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>如果经常需要用</span><span lang=EN-US>dynamic_cast</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>(或不带检查的</span><span lang=EN-US>static_cast</span><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><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 style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>有些情况无法在编译时进行检查,因此需要运行时检查。对这些情况,最好用断言来检测内部的编程错误,另外对其它的运行时错误,如依赖于数据的错误,请遵循错误处理一节中的其余条目(参见第</span><span
lang=EN-US>69</span><span style='font-family:宋体;mso-ascii-font-family:"Times New Roman";
mso-hansi-font-family:"Times New Roman"'>至</span><span lang=EN-US>75</span><span
style='font-family:宋体;mso-ascii-font-family:"Times New Roman";mso-hansi-font-family:
"Times New Roman"'>条)。</span></p>
</div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -