C++异常详解

handlers.

To catch exceptions we must place a portion of code under exception inspection. This is done by enclosing that portion of code in a  try block. When an exceptional circumstance arises within that block, an exception is thrown that transfers the control to the exception handler. If no exception is thrown, the code continues normally and all handlers are ignored.

An exception is thrown by using the throw keyword from inside the try block. Exception handlers are declared with the keyword  catch, which must be placed immediately after the try block:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// exceptions
#include <iostream>
using namespace std;

int main () {
  try
  {
    throw 20;
  }
  catch (int e)
  {
    cout << "An exception occurred. Exception Nr. " << e << endl;
  }
  return 0;
}
An exception occurred. Exception Nr. 20


The code under exception handling is enclosed in a  try block. In this example this code simply throws an exception:

 
throw 20;


A throw expression accepts one parameter (in this case the integer value  20), which is passed as an argument to the exception handler.

The exception handler is declared with the  catch keyword. As you can see, it follows immediately the closing brace of the  try block. The catch format is similar to a regular function that always has at least one parameter. The type of this parameter is very important, since the type of the argument passed by the throw expression is checked against it, and only in the case they match, the exception is caught.

We can chain multiple handlers (catch expressions), each one with a different parameter type. Only the handler that matches its type with the argument specified in the throw statement is executed.

If we use an ellipsis ( ...) as the parameter of  catch, that handler will catch any exception no matter what the type of the  throw exception is. This can be used as a default handler that catches all exceptions not caught by other handlers if it is specified at last:

1
2
3
4
5
6
try {
  // code here
}
catch (int param) { cout << "int exception"; }
catch (char param) { cout << "char exception"; }
catch (...) { cout << "default exception"; }


In this case the last handler would catch any exception thrown with any parameter that is neither an  int nor a  char.

After an exception has been handled the program execution resumes after the  try-catch block, not after the  throw statement!.

It is also possible to nest  try-catch blocks within more external  try blocks. In these cases, we have the possibility that an internal  catch block forwards the exception to its external level. This is done with the expression  throw; with no arguments. For example: 

1
2
3
4
5
6
7
8
9
10
11
try {
  try {
      // code here
  }
  catch (int n) {
      throw;
  }
}
catch (...) {
  cout << "Exception occurred";
}


Exception specifications


When declaring a function we can limit the exception type it might directly or indirectly throw by appending a  throw suffix to the function declaration:

 
float myfunction (char param) throw (int);


This declares a function called  myfunction which takes one agument of type  char and returns an element of type  float. The only exception that this function might throw is an exception of type  int. If it throws an exception with a different type, either directly or indirectly, it cannot be caught by a regular  int-type handler.

If this  throw specifier is left empty with no type, this means the function is not allowed to throw exceptions. Functions with no  throw specifier (regular functions) are allowed to throw exceptions with any type:

1
2
int myfunction (int param) throw(); // no exceptions allowed
int myfunction (int param);         // all exceptions allowed 


Standard exceptions

The C++ Standard library provides a base class specifically designed to declare objects to be thrown as exceptions. It is called  exception and is defined in the  <exception>header file under the  namespace std. This class has the usual default and copy constructors, operators and destructors, plus an additional virtual member function called  whatthat returns a null-terminated character sequence ( char *) and that can be overwritten in derived classes to contain some sort of description of the exception.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
  virtual const char* what() const throw()
  {
    return "My exception happened";
  }
} myex;

int main () {
  try
  {
    throw myex;
  }
  catch (exception& e)
  {
    cout << e.what() << endl;
  }
  return 0;
}
My exception happened.


We have placed a handler that catches exception objects by reference (notice the ampersand  & after the type), therefore this catches also classes derived from  exception, like our  myex object of class  myexception.

All exceptions thrown by components of the C++ Standard library throw exceptions derived from this  std::exception class. These are:

exception description
bad_alloc thrown by new on allocation failure
bad_cast thrown by dynamic_cast when fails with a referenced type
bad_exception thrown when an exception type doesn't match any catch
bad_typeid thrown by typeid
ios_base::failure thrown by functions in the iostream library

For example, if we use the operator  new and the memory cannot be allocated, an exception of type  bad_alloc is thrown:

1
2
3
4
5
6
7
8
try
{
  int * myarray= new int[1000];
}
catch (bad_alloc&)
{
  cout << "Error allocating memory." << endl;
}


It is recommended to include all dynamic memory allocations within a try block that catches this type of exception to perform a clean action instead of an abnormal program termination, which is what happens when this type of exception is thrown and not caught. If you want to force a  bad_alloc exception to see it in action, you can try to allocate a huge array; On my system, trying to allocate 1 billion  ints threw a  bad_alloc exception.

Because  bad_alloc is derived from the standard base class  exception, we can handle that same exception by catching references to the  exception class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// bad_alloc standard exception
#include <iostream>
#include <exception>
using namespace std;

int main () {
  try
  {
    int* myarray= new int[1000];
  }
  catch (exception& e)
  {
    cout << "Standard exception: " << e.what() << endl;
  }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值