📄 cargill.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/frameset.dtd">
<HTML LANG="en">
<HEAD>
<LINK REL=STYLESHEET HREF=../INTRO/ECMEC.CSS>
<TITLE>Exception Handling: A False Sense of Security. By Tom Cargill</TITLE>
<SCRIPT LANGUAGE="JavaScript" SRC="../JAVA/COOKIE.JS"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript">var imagemax = 0; setCurrentMax(0);</SCRIPT>
<SCRIPT LANGUAGE="JavaScript" SRC="../JAVA/DINGBATS.JS"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript" SRC="../JAVA/SENDMETO.JS"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript">
var dingbase = "CA_DIR.HTM";
var dingtext = "Cargill, P";
if (self == top) {
top.location.replace(dingbase + this.location.hash);
}
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#ffffff" ONLOAD="setResize()">
<!-- SectionName="Cargill's EH: A False Sense of Security" -->
<HR SIZE="1" NOSHADE>
<FONT COLOR="#663300" FACE="Helvetica" SIZE=-1>
<B>This is a slightly modified version of an article that appeared in the November-December 1994 issue of the <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><I><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=cppreport" ONMOUSEOVER="self.status='C++ Report Home Page'; return true" ONMOUSEOUT="self.status = self.defaultStatus" TARGET="_top">C++</NOBR> Report</A></I></B>.
</FONT>
<HR SIZE="1" NOSHADE>
<P><A NAME="dingp1"></A><FONT ID="agtitle">Exception Handling: A False Sense of Security</FONT><SCRIPT>create_link(1);</SCRIPT>
</P>
<P><A NAME="dingp2"></A><A NAME="AUTO00001"></A><FONT FACE="Arial" SIZE="+1">by </FONT><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><FONT FACE="Arial" SIZE="+1"><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=cargill" ONMOUSEOVER = "self.status = 'Tom Cargill Home Page'; return true" ONMOUSEOUT = "self.status = self.defaultStatus" TARGET="_top">Tom Cargill</A></FONT><SCRIPT>create_link(2);</SCRIPT>
</P>
</FONT>
<P><A NAME="dingp3"></A><A NAME="AUTO00002"></A>I suspect that most members of the C++ community vastly underestimate the skills needed to program with exceptions and therefore underestimate the true costs of their use. The popular belief is that exceptions provide a straightforward mechanism for adding reliable error handling to our programs. On the contrary, I see exceptions as a mechanism that may cause more ills than it cures. Without extraordinary care, the addition of exceptions to most software is likely to diminish overall reliability and impede the software development <NOBR>process.<SCRIPT>create_link(3);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp4"></A><A NAME="AUTO00003"></A>This "extraordinary care" demanded by exceptions originates in the subtle interactions among language features that can arise in exception handling. Counter-intuitively, the hard part of coding exceptions is not the explicit throws and catches. The really hard part of using exceptions is to write all the intervening code in such a way that an arbitrary exception can propagate from its throw site to its handler, arriving safely and without damaging other parts of the program along the <NOBR>way.<SCRIPT>create_link(4);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp5"></A><A NAME="AUTO00004"></A>In the October 1993 issue of the <NOBR><FONT COLOR="#FF0000" SIZE="-2"><B>°</B></FONT><A HREF="http://www.awl.com/cseng/cgi-bin/cdquery.pl?name=cppreport" ONMOUSEOVER = "self.status = 'C++ Report Home Page'; return true" ONMOUSEOUT = "self.status = self.defaultStatus" TARGET="_top"><EM>C++</NOBR> Report</EM></A>, David Reed argues in favor of exceptions saying that: "Robust reusable types require a robust error handling mechanism that can be used in a consistent way across different reusable class libraries." While entirely in favor of robust error handling, I have serious doubts that exceptions will engender software that is any more robust than that achieved by other means. I am concerned that exceptions will lull programmers into a false sense of security, believing that their code is handling errors when in reality the exceptions are actually compounding errors and hindering the <NOBR>software.<SCRIPT>create_link(5);</SCRIPT>
</NOBR></P>
<P><A NAME="dingp6"></A><A NAME="AUTO00005"></A>To illustrate my concerns concretely I will examine the code that appeared in Reed's article. The code (page 42, October 1993) is a <CODE>Stack</CODE> class template. To reduce the size of Reed's code for presentation purposes, I have made two changes. First, instead of throwing <CODE>Exception</CODE> objects, my version simply throws literal character strings. The detailed encoding of the exception object is irrelevant for my purposes, because we will see no extraction of information from an exception object. Second, to avoid having to break long lines of source text, I have abbreviated the identifier <CODE>current_index</CODE> to <CODE>top</CODE>. Reed's code follows. Spend a few minutes studying it before reading on. Pay particular attention to its exception handling. [Hint: Look for any of the classic problems associated with <CODE>delete</CODE>, such as too few <CODE>delete</CODE> operations, too many <CODE>delete</CODE> operations or access to memory after its <CODE>delete</CODE>.]<SCRIPT>create_link(6);</SCRIPT>
</P>
<A NAME="AUTO00006"></A>
<TABLE ALIGN="center" WIDTH="95%" BORDER="0" CELLSPACING="3" CELLPADDING="3">
<TR><TH BGCOLOR="#000000"><FONT COLOR="#FFFFFF">Original Code for Stack Template</FONT></TH></TR>
<TR><TD BGCOLOR="#FFFFCC">
<A NAME="AUTO00023"></A><PRE>
template <class T>
class Stack
{
unsigned nelems;
int top;
T* v;
public:
unsigned count();
void push(T);
T pop();
Stack();
~Stack();
Stack(const Stack&);
Stack& operator=(const Stack&);
};
template <class T>
Stack<T>::Stack()
{
top = -1;
v = new T[nelems=10];
if( v == 0 )
throw "out of memory";
}
template <class T>
Stack<T>::Stack(const Stack<T>& s)
{
v = new T[nelems = s.nelems];
if( v == 0 )
throw "out of memory";
if( s.top > -1 ){
for(top = 0; top <= s.top; top++)
v[top] = s.v[top];
top--;
}
}
template <class T>
Stack<T>::~Stack()
{
delete [ ] v;
}
template <class T>
void Stack<T>::push(T element)
{
top++;
if( top == nelems-1 ){
T* new_buffer = new T[nelems+=10];
if( new_buffer == 0 )
throw "out of memory";
for(int i = 0; i < top; i++)
new_buffer[i] = v[i];
delete [ ] v;
v = new_buffer;
}
v[top] = element;
}
template <class T>
T Stack<T>::pop()
{
if( top < 0 )
throw "pop on empty stack";
return v[top--];
}
template <class T>
unsigned Stack<T>::count()
{
return top+1;
}
template <class T>
Stack<T>&
Stack<T>::operator=(const Stack<T>& s)
{
delete [ ] v;
v = new T[nelems=s.nelems];
if( v == 0 )
throw "out of memory";
if( s.top > -1 ){
for(top = 0; top <= s.top; top++)
v[top] = s.v[top];
top--;
}
return *this;
}</PRE>
</TD></TR></TABLE>
<P><A NAME="dingp7"></A><A NAME="AUTO00007"></A>My examination of the code is in three phases. First, I study the code's behavior along its "normal", exception-free execution paths, those in which no exceptions are thrown. Second, I study the consequences of exceptions thrown explicitly by the member functions of <CODE>Stack</CODE>. Third, I study the consequences of exceptions thrown by the <CODE>T</CODE> objects that are manipulated by <CODE>Stack</CODE>. Of these three phases, it is unquestionably the third that involves the most demanding <NOBR>analysis.<SCRIPT>create_link(7);</SCRIPT>
</NOBR></P>
<A NAME="AUTO00008"></A>
<P><A NAME="dingp8"></A><FONT ID="aititle">Normal Execution Paths</FONT><SCRIPT>create_link(8);</SCRIPT>
</P>
<P><A NAME="dingp9"></A>Consider the following code, which uses the copy constructor to make a copy of an empty <NOBR>stack:<SCRIPT>create_link(9);</SCRIPT>
</NOBR></P>
<BR>
<A NAME="AUTO00009"></A>
<A NAME="AUTO00024"></A><UL><PRE>
Stack<int> y;
Stack<int> x = y;
assert( y.count() == 0 );
printf( "%u\n", x.count() );</PRE>
</UL>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -