1

My sample code:

#include<iostream>
using namespace std;

class Test{ public: int set;};
Test T;

int main()
{
    T.set = 100;
    try{
        throw T;
    }
    catch(Test &T)
    {
        T.set = 0;
    }
    cout<<T.set<<endl;
    return 1;
}

Here I am catching the thrown T object by reference and modifying its value inside the catch block. Why does the T object still prints 100 after the catch block? What is the use of reference syntax in this case over pass by value?

compiler: gcc 5.1.0

Sreeraj Chundayil
  • 5,548
  • 3
  • 29
  • 68

2 Answers2

8

You are catching the exception object by reference, but not throwing it as such.

Exceptions are always "thrown by value", because they must be allocated in a special region of your process's memory that is immune to the effects of stack unwinding.

[C++14: 15.1/3]: Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler (15.3). [..]

This is a general rule that is designed to account for the far more common case in which T is actually local to either the try block itself or its encapsulating function. It would be impossible to catch it from calling scopes if it were not copied.

We catch the exception object by reference so that you don't needlessly copy again the already-copied T. It also prevents slicing when your exceptions are in an inheritance heirarchy. Sometimes people use it to mutate the exception object before re-throwing it to calling scopes, though this appears to be a rarity.

Catching it by reference-to-const has the same benefit as catching any other thing by reference-to-const: it ensures that you do not mutate the exception. If you're not rethrowing it then there's no practical benefit here but if, like me, you write const by default as a fail-safe against mistakes, there's no reason not to use it.

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

Why does the T object still prints 100 after the catch block?

Because throwing is by value, creating a copy.

What is the use of reference syntax in this case over pass by value?

Nothing.

Catching by reference to constis a good rule of thumb, because it's generally efficient and safe.

The above, as the code was when I wrote this, doesn't catch by reference to const, so it's just (1)ungood practice.


In passing, talking of good practice, using all uppercase names risks collision with macro names, and (in this case misguidingly) indicates macro to a trained reader.

Single letter uppercase names, and in particular T, is to some degree a special case, because they have by convention been used for template parameters, so they're unlikely to be used as macro names.

Still, I recommend the old convention, all uppercase for macros, always, and mixed or lowercase for anything else.


1) At one time the wording of the C++98 and C++03 standards could be interpreted in a way where only catching by reference to non-const guaranteed efficiency. It was a peculiar interpretation but advocated by at least one well-known C++ person. It's just of historic interest now.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • If it is passed by value, why do we have to make it const. We can't modify the actual object anyway – Sreeraj Chundayil Jul 26 '15 at 14:33
  • 1
    What is the benefit of catching by const reference, instead of non-const? People claim this regularly but nobody is ever able to justify it, instead waving their hands and saying "efficiency" – M.M Jul 26 '15 at 14:33
  • @InQusitive: Yes, you can. You can mutate it and rethrow it. You can't modify the _original_ object but that's pretty much irrelevant. – Lightness Races in Orbit Jul 26 '15 at 14:33
  • @MattMcNabb: Personally I see none. I do it only because I use `const` by default. – Lightness Races in Orbit Jul 26 '15 at 14:33
  • @MattMcNabb: The `const` is for safety and clarity. It tells a reader of the code that the exception object will not be mutated. With good standard exceptions that's not so much of an issue, but it becomes important practice when using other exception classes. – Cheers and hth. - Alf Jul 26 '15 at 14:42
  • 1
    Can you give an example of a problem that could arise? – M.M Jul 26 '15 at 14:51
  • @MattMcNabb: Once you start down the path marked "mutating exception objects" it's not far till you get to broken-expectations land and needless-checking-of-cases land. Correctness is no longer centralized in the exception object itself but involves a not-apparent communication contract beween one handler (mutator) and another handler (final consumer). Even if that works someone reading the code may have to expend some wasted time on figuring out what's going on. – Cheers and hth. - Alf Jul 26 '15 at 15:04