new
main()
calls a.GetValue()
, which calls
a.myData.Get()
, which calls cin.operator>>()
,
etc.
try
block" and looks like
this:
void must_succeed(int data)
{
do_something_safe();
List<int> list;
list.Append(data);
try
{
data = do_something_risky(data);
list.RiskyMethod(data);
// OTHER RISKY STUFF
}
list.SafeMethod();
}
try
block)
throw
statement:
class DivByZero
{};
int do_something_risky(int data)
{
if (data==0)
{
DivByZero exception;
throw exception;
}
return data-1/data;
}
class NegativeIndex
{
public:
NegativeIndex(int index, string context)
: myIndex(index), myContext(context)
{}
int myIndex;
string myContext;
};
template <DATATYPE>
DATATYPE
List<DATATYPE>::RiskyMethod(int index)
{
if (index<0)
{
NegativeIndex exception(index,"do_something_risky(int)");
throw exception;
}
return myValues[index];
}
catch
blocks after a try
block:
try
{
data = do_something_risky(data);
list.RiskyMethod(data);
// OTHER RISKY STUFF
}
catch (DivByZero)
{
cout << "Can't divide by zero, stupid!" << endl;
}
catch (NegativeIndex exception)
{
cout << "Can't access element " << exception.myIndex
<< " in function " << exception.myContext << endl;
}
catch (...)
{
cout << "Don't know what you did, but it was bad!" << endl;
}
catch
blocks acts almost like a switch
which is triggered by an exception¤ inside the try
block
(except that the sequence "switches" on the type of the
exception¤, not its value).
catch
block catches any type of exception¤.
catch
block is specified for a particular kind
of exception¤, it "slips through the net" and continues
propagating up the call sequence.
catch
targets:
try
{
data = do_something_risky(data);
list.RiskyMethod(data);
// OTHER RISKY STUFF
}
catch (NumericException&)
{
cout << "You did something dumb with a number!" << endl;
}
catch (IndexException& exception)
{
cout << exception.Message() << endl;
}
NumericException
or an IndexException
will be caught.
class NumericException
{};
class DivByZero : public NumericException
{};
class NegativeLog: public NumericException
{};
class IndexException
{
public:
virtual string Message(void)
{
return "You did something stupid with an index";
}
};
class NegativeIndex : public IndexException
{
public:
NegativeIndex(int index, string context)
: myIndex(index), myContext(context)
{}
virtual string Message(void)
{
stringstream message;
message << "Can't index element "
<< myIndex
<< " (like you tried to do in "
<< myContext
<< ", dopey!";
return message.str();
}
int myIndex;
string myContext;
};
new
new
operator uses exceptions¤ to signal
problems (unlike malloc
which just returns
a zero in such cases)
bad_alloc
try
{
ptr = new SomeClass;
}
catch (bad_alloc)
{
// DO SOMETHING ABOUT IT
}
template <class ELEMENTTYPE>
class Array
{
public:
struct OutOfRange
{
int bad_index;
};
// YADDA YADDA
ELEMENTTYPE operator[](int index)
{
if (index<0 || index>=mySize)
{
OutOfRange oor;
oor.bad_index = index;
throw oor;
}
return myData[index];
}
// YADDA YADDA
};
Array<int> ai;
// AND LATER...
int nextindex;
while (cin >> nextindex)
{
try
{
cout << ai[nextindex] << endl;
}
catch (Array<int>::OutOfRange exception)
{
cout << "Index " << exception.bad_index
<< "was not in allowed range;
}
}