Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catching exceptions by reference

In this C++ tutorial, in the section titled "Standard exceptions", there is this example code which uses a class derived from the standard exception class in the STL:

// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception
{
  virtual const char* what() const throw()
  {
    return "My exception happened";
  }
} myex; //Declares an instance of myexception outside of the main function

int main () {
  try
  {
    throw myex;
  }
  catch (exception& e) //My question is regarding this line of code
  {
    cout << e.what() << endl;
  }
  return 0;
}

That code prints out My exception happened. However, if I remove the ampersand, it prints out std::exception, which is what happens when you call what() with the standard exception class, not the derived class.

The website gives this explanation:

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.

Is throwing myex kind of like "calling a the catch function, and passing myex as a parameter"? Because it that case, I would imagine that it doesn't matter whether you throw the exception by value or by reference (that's what the ampersand does right?), because you are still throwing a myexception rather than an exception. And due to dynamic binding and polymorphism or something like that, e.what() should still print out My exception happened rather than std::exception.

like image 301
newprogrammer Avatar asked Dec 02 '11 00:12

newprogrammer


2 Answers

This is happening due to object slicing.

If you assign an object of a derived class to an instance of a base class (as in the case of using a copy c'tor when passing by value) all the information of the derived class will be lost (sliced).

For example,

class Base {
   int baseInfo;
};

class Derived : public Base
{
   int someInfo;
};

Then if you were to write this:

Derived myDerivedInstance;

Base baseInstance = myDerivedInstance;

Then the "someInfo" in myDerivedInstance is sliced away in baseInstance.

like image 162
FailedDev Avatar answered Sep 19 '22 00:09

FailedDev


You can kind of think of it like that, but (like a function call), the exception is passed by value to the catch handler. Since it's passed by value, it's copied to a std::exception local to the catch handler. It does that with std::exceptions copy constructor, in which case the copy no longer has any private data held by a myexception, nor the derived functions. Functions do the exact same thing. This is called "object slicing", and is why you never store virtual base types by value, only by pointer or reference. You'd see the same behavior with a std::vector<std::exception>. Contained elements would lose all derived data.

like image 42
Mooing Duck Avatar answered Sep 18 '22 00:09

Mooing Duck