Exception Handling

I was going through the exception handling tutorial on this site. Can somebody please explain the difference between the below two approaches?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class myexception: public exception
{
public:
  virtual const char* what() const throw()
  {
    return "My exception happened";
  }
} myex;

int main () {
  try
  {
    throw myex;
  }
  catch (myexception e)
  {
    cout << e.what() << endl;
  }
  return 0;
}


and this approach:

1
2
3
4
5
6
7
8
9
10
int main () {
  try
  {
    throw myex;
  }
  catch (exception& e)
  {
    cout << e.what() << endl;
  }
  return 0;
The first will only catch instances of myexception. The second will catch all children of std::exception. This works thanks to polymorphism.
Thank you, so does this imply that the second one catches instances of all child classes of 'exception' i.e if I had another child class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class myexception2: public exception
{
public:
  virtual const char* what() const throw()
  {
    return "My exception happened";
  }
} myex2;

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


would catch myex2 as well..

also any examples of where this might be useful?
Yes.

This is useful when you don't know or don't care what could be thrown, for example, if no matter what is thrown, you're going to exit the program.
> Can somebody please explain the difference between the below two approaches?

The exception declaration in a handler is similar to the parameter declaration of a unary function. The differences are: 1. r-value references are not permitted. 2. No conversions other than derived class to base class conversions and ignoring top-level cv-qualifiers are performed 3. Entry into handlers are attempted in order of appearance during the stack unwind - ie. there is no overload resolution.

1
2
3
4
5
6
7
8
9
10
void function( A ) ; // A is passed by value
void function( A& ) ; // A is passed by reference
void function( const A& ) ; // A is passed by reference to const

// ...

try { /* ... */ }
catch( A ) { /* ... */ } // A is caught by value
catch( A& ) { /* ... */ } // A is caught by reference
catch( const A& ) { /* ... */ } // A is caught by reference to const 



> also any examples of where this might be useful?

The canonical exception declaration in a handler is of the form:
catch( const T& r ).

This has several advantages: T can be an abstract interface; virtual functions invoked on r will behave polymorphically; and it avoids an operation that may fail (copy construction of the object) during stack unwind and the consequent call of unexpected()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <typeinfo>

struct base
{
    base() {}
    base( const base& ) { std::cout << "base::copy constructor\n" ; }
    virtual ~base() { std::cout << "base::destructor\n" ; }
};

struct derived : virtual base
{
    derived() { std::cout << "derived::constructor\n" ; }
    ~derived() { std::cout << "derived::destructor which invokes " ; }
} ;

void foo()
{
    std::cout << "\n-----------  foo -----------------\n" ;
    try { throw derived() ; } // copy-elision is applied here
    catch( base a ) // catches base by value
    // the derived that was thrown is sliced to create a new object of type base
    {
        std::cout << "caught object of type: " << typeid(a).name() << '\n' ;
    }
}

void bar()
{
    std::cout << "\n-----------  bar -----------------\n" ;
    try { throw derived() ; } // copy-elision is applied here
    catch( const base& a ) // catches base by reference to const
    // what is caught is the derived that was thrown - no new object is created
    {
        std::cout << "caught object of type: " << typeid(a).name() << '\n' ;
    }
}

int main()
{
    foo() ;
    bar() ;
}


Output:

-----------  foo -----------------
derived::constructor
base::copy constructor
caught object of type: 4base
base::destructor
derived::destructor which invokes base::destructor

-----------  bar -----------------
derived::constructor
caught object of type: 7derived
derived::destructor which invokes base::destructor
Topic archived. No new replies allowed.