📄 chap01.htm
字号:
<font color=#0000ff>public</font>:
UseResources(<font color=#0000ff>int</font> count = 1) {
out << <font color=#004488>"UseResources()"</font> << endl;
bp = <font color=#0000ff>new</font> Cat[count];
op = <font color=#0000ff>new</font> Dog;
}
~UseResources() {
out << <font color=#004488>"~UseResources()"</font> << endl;
<font color=#0000ff>delete</font> []bp; <font color=#009900>// Array delete</font>
<font color=#0000ff>delete</font> op;
}
};
<font color=#0000ff>int</font> main() {
<font color=#0000ff>try</font> {
UseResources ur(3);
} <font color=#0000ff>catch</font>(<font color=#0000ff>int</font>) {
out << <font color=#004488>"inside handler"</font> << endl;
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The output is the
following:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>UseResources()
Cat()
Cat()
Cat()
allocating a Dog
inside handler</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>UseResources</B> constructor is
entered, and the <B>Cat</B> constructor is successfully completed for the array
objects. However, inside <B>Dog::operator new</B>, an exception is thrown (as an
example of an out-of-memory error). Suddenly, you end up inside the handler,
<I>without</I> the <B>UseResources</B> destructor being called. This is correct
because the <B>UseResources</B> constructor was unable to finish, but it means
the <B>Cat</B> object that was successfully created on the heap is never
destroyed.</FONT><A NAME="_Toc312374123"></A><A NAME="_Toc519041893"></A><BR></P></DIV>
<A NAME="Heading37"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H3 ALIGN="LEFT">
Making everything an object</H3></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To prevent this, guard against these
“raw” resource allocations by placing the allocations inside their
own objects with their own constructors and destructors. This way, each
allocation becomes atomic<A NAME="Index77"></A>, as an object, and if it fails,
the other resource allocation objects are properly cleaned up. Templates are an
excellent way to modify the above example:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C01:Wrapped.cpp</font>
<font color=#009900>// Safe, atomic pointers</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <fstream>
#include <cstdlib>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
ofstream out(<font color=#004488>"wrapped.out"</font>);
<font color=#009900>// Simplified. Yours may have other arguments.</font>
<font color=#0000ff>template</font><<font color=#0000ff>class</font> T, <font color=#0000ff>int</font> sz = 1> <font color=#0000ff>class</font> PWrap {
T* ptr;
<font color=#0000ff>public</font>:
<font color=#0000ff>class</font> RangeError {}; <font color=#009900>// Exception class</font>
PWrap() {
ptr = <font color=#0000ff>new</font> T[sz];
out << <font color=#004488>"PWrap constructor"</font> << endl;
}
~PWrap() {
<font color=#0000ff>delete</font> []ptr;
out << <font color=#004488>"PWrap destructor"</font> << endl;
}
T& <font color=#0000ff>operator</font>[](<font color=#0000ff>int</font> i) <font color=#0000ff>throw</font>(RangeError) {
<font color=#0000ff>if</font>(i >= 0 && i < sz) <font color=#0000ff>return</font> ptr[i];
<font color=#0000ff>throw</font> RangeError();
}
};
<font color=#0000ff>class</font> Cat {
<font color=#0000ff>public</font>:
Cat() { out << <font color=#004488>"Cat()"</font> << endl; }
~Cat() { out << <font color=#004488>"~Cat()"</font> << endl; }
<font color=#0000ff>void</font> g() {}
};
<font color=#0000ff>class</font> Dog {
<font color=#0000ff>public</font>:
<font color=#0000ff>void</font>* <font color=#0000ff>operator</font> <font color=#0000ff>new</font>[](size_t sz) {
out << <font color=#004488>"allocating an Dog"</font> << endl;
<font color=#0000ff>throw</font> <font color=#0000ff>int</font>(47);
}
<font color=#0000ff>void</font> <font color=#0000ff>operator</font> <font color=#0000ff>delete</font>[](<font color=#0000ff>void</font>* p) {
out << <font color=#004488>"deallocating an Dog"</font> << endl;
::<font color=#0000ff>delete</font> p;
}
};
<font color=#0000ff>class</font> UseResources {
PWrap<Cat, 3> Bonk;
PWrap<Dog> Og;
<font color=#0000ff>public</font>:
UseResources() : Bonk(), Og() {
out << <font color=#004488>"UseResources()"</font> << endl;
}
~UseResources() {
out << <font color=#004488>"~UseResources()"</font> << endl;
}
<font color=#0000ff>void</font> f() { Bonk[1].g(); }
};
<font color=#0000ff>int</font> main() {
<font color=#0000ff>try</font> {
UseResources ur;
} <font color=#0000ff>catch</font>(<font color=#0000ff>int</font>) {
out << <font color=#004488>"inside handler"</font> << endl;
} <font color=#0000ff>catch</font>(...) {
out << <font color=#004488>"inside catch(...)"</font> << endl;
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The difference is the use of the template
to wrap the pointers and make them into objects. The constructors for these
objects are called <I>before</I> the body of the <B>UseResources</B>
constructor, and any of these constructors that complete before an exception is
thrown will have their associated destructors called.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The <B>PWrap</B> template shows a more
typical use of exceptions than you’ve seen so far: A nested class called
<B>RangeError</B> is created to use in <B>operator[ ]<A NAME="Index78"></A></B>
if its argument is out of range. Because <B>operator[ ]</B> returns a
reference<A NAME="Index79"></A><A NAME="Index80"></A> it cannot return zero.
(There are no null references.) This is a true exceptional condition – you
don’t know what to do in the current context, and you can’t return
an improbable value. In this example, <B>RangeError</B> is very simple and
assumes all the necessary information is in the class name, but you may also
want to add a member that contains the value of the index, if that is
useful.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Now the output is</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE>Cat()
Cat()
Cat()
PWrap constructor
allocating a Dog
~Cat()
~Cat()
~Cat()
PWrap destructor
inside handler</PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Again, the storage allocation for
<B>Dog</B> throws an exception, but this time the array of <B>Cat</B> objects is
properly cleaned up, so there is no memory
leak.</FONT><A NAME="_Toc305593301"></A><A NAME="_Toc305628773"></A><A NAME="_Toc312374124"></A><A NAME="_Toc519041894"></A><BR></P></DIV>
<A NAME="Heading38"></A><FONT FACE = "Verdana, Tahoma, Arial, Helvetica, Sans"><H2 ALIGN="LEFT">
Exception matching<BR><A NAME="Index81"></A></H2></FONT>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">When an exception is thrown, the
exception-handling system looks through the “nearest” handlers in
the order they are written. When it finds a match, the exception is considered
handled, and no further searching occurs. </FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Matching an exception doesn’t
require a perfect match between the exception and its handler. An object or
reference to a derived-class object will match a handler for the base class.
(However, if the handler is for an object rather than a reference, the exception
object is “sliced”
<A NAME="Index82"></A><A NAME="Index83"></A><A NAME="Index84"></A>as it is
passed to the handler; this does no damage but loses all the derived-type
information.) If a pointer is thrown, standard pointer conversions are used to
match the exception. However, no automatic type conversions
<A NAME="Index85"></A><A NAME="Index86"></A><A NAME="Index87"></A><A NAME="Index88"></A>are
used to convert one exception type to another in the process of matching. For
example,</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C01:Autoexcp.cpp</font>
<font color=#009900>// No matching conversions</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> Except1 {};
<font color=#0000ff>class</font> Except2 {
<font color=#0000ff>public</font>:
Except2(Except1&) {}
};
<font color=#0000ff>void</font> f() { <font color=#0000ff>throw</font> Except1(); }
<font color=#0000ff>int</font> main() {
<font color=#0000ff>try</font> { f();
} <font color=#0000ff>catch</font> (Except2) {
cout << <font color=#004488>"inside catch(Except2)"</font> << endl;
} <font color=#0000ff>catch</font> (Except1) {
cout << <font color=#004488>"inside catch(Except1)"</font> << endl;
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Even though you might think the first
handler could be used by converting an <B>Except1</B> object into an
<B>Except2</B> using the constructor conversion, the system will not perform
such a conversion during exception handling, and you’ll end up at the
<B>Except1</B> handler.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><A NAME="Index89"></A><A NAME="Index90"></A><FONT FACE="Georgia">The
following example shows how a base-class handler can catch a derived-class
exception:</FONT><BR></P></DIV>
<BLOCKQUOTE><FONT SIZE = "+1"><PRE><font color=#009900>//: C01:Basexcpt.cpp</font>
<font color=#009900>// Exception hierarchies</font>
<font color=#009900>//{L} ../TestSuite/Test</font>
#include <iostream>
<font color=#0000ff>using</font> <font color=#0000ff>namespace</font> std;
<font color=#0000ff>class</font> X {
<font color=#0000ff>public</font>:
<font color=#0000ff>class</font> Trouble {};
<font color=#0000ff>class</font> Small : <font color=#0000ff>public</font> Trouble {};
<font color=#0000ff>class</font> Big : <font color=#0000ff>public</font> Trouble {};
<font color=#0000ff>void</font> f() { <font color=#0000ff>throw</font> Big(); }
};
<font color=#0000ff>int</font> main() {
X x;
<font color=#0000ff>try</font> {
x.f();
} <font color=#0000ff>catch</font>(X::Trouble) {
cout << <font color=#004488>"caught Trouble"</font> << endl;
<font color=#009900>// Hidden by previous handler:</font>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -