2

In the following code, the exceptions are thrown in two cases as shown in the main ().

#include <iostream>

// Our own exception classes - just for fun.
class myExceptionClassA 
{
    public:
    myExceptionClassA () {std::cout << "\nWarning: Division by zero isn't allowed.\n";}
};

class myExceptionClassB
{
    public:
    myExceptionClassB () {std::cout << "\nWarning: Division by dividend isn't allowed.\n";}
};

class divisionClass
{
    private:
    int *result;

    public:
    divisionClass () 
    {
        // Allocating memory to the private variable.
        result = new int;
    }

    /* 
        The class function `doDivide`:
        1. Throws above defined exceptions on the specified cases.
        2. Returns the division result.
    */
    int doDivide (int toBeDividedBy) throw (myExceptionClassA, myExceptionClassB)
    {
        *result       = 200000;

        // If the divisor is 0, then throw an exception.
        if (toBeDividedBy == 0)
        {
            throw myExceptionClassA ();
        }
        // If the divisor is same as dividend, then throw an exception.
        else if (toBeDividedBy == *result)
        {
            throw myExceptionClassB ();
        }

        // The following code won't get executed if/when an exception is thrown.
        std :: cout <<"\nException wasn't thrown. :)";

        *result = *result / toBeDividedBy;
        return *result;
    }

    ~divisionClass () 
    {
        std::cout << "\ndddddddddd\n";
        delete result;
    }
};

int main ()
{
    divisionClass obj;
    try
    {
        obj.doDivide (200000);
    }
    catch (myExceptionClassA) {}
    catch (myExceptionClassB) {}

    try
    {
        obj.doDivide (3);
    }
    catch (myExceptionClassA) {}
    catch (myExceptionClassB) {}

    try
    {
        obj.doDivide (0);
    }
    catch (myExceptionClassA) {}
    catch (myExceptionClassB) {}

    try
    {
        obj.doDivide (4);
    }
    catch (myExceptionClassA) {}
    catch (myExceptionClassB) {}

    return 0;
}

- The both exception class print statements get printed.
- The statement in the destructor gets printed only once.
- Valgrind doesn't show any memory leaks.

anisha@linux-y3pi:~/Desktop> g++ exceptionSafe3.cpp -Wall
anisha@linux-y3pi:~/Desktop> valgrind ./a.out 
==18838== Memcheck, a memory error detector
==18838== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==18838== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==18838== Command: ./a.out
==18838== 

Warning: Division by dividend isn't allowed.

Exception wasn't thrown. :)
Warning: Division by zero isn't allowed.

Exception wasn't thrown. :)
dddddddddd
==18838== 
==18838== HEAP SUMMARY:
==18838==     in use at exit: 0 bytes in 0 blocks
==18838==   total heap usage: 3 allocs, 3 frees, 262 bytes allocated
==18838== 
==18838== All heap blocks were freed -- no leaks are possible
==18838== 
==18838== For counts of detected and suppressed errors, rerun with: -v
==18838== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
anisha@linux-y3pi:~/Desktop> 

Shouldn't the destructor get called 3 times - two times for exceptions and one time for return statement?

Please explain the point that I am missing.


Now I tried it by removing all the try catch blocks in the main().
Destructor doesn't get called at all?

anisha@linux-y3pi:~/Desktop> valgrind ./a.out 
==18994== Memcheck, a memory error detector
==18994== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==18994== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==18994== Command: ./a.out
==18994== 

Warning: Division by dividend isn't allowed.
terminate called after throwing an instance of 'myExceptionClassB'
==18994== 
==18994== HEAP SUMMARY:
==18994==     in use at exit: 133 bytes in 2 blocks
==18994==   total heap usage: 3 allocs, 1 frees, 165 bytes allocated
==18994== 
==18994== LEAK SUMMARY:
==18994==    definitely lost: 0 bytes in 0 blocks
==18994==    indirectly lost: 0 bytes in 0 blocks
==18994==      possibly lost: 129 bytes in 1 blocks
==18994==    still reachable: 4 bytes in 1 blocks
==18994==         suppressed: 0 bytes in 0 blocks
==18994== Rerun with --leak-check=full to see details of leaked memory
==18994== 
==18994== For counts of detected and suppressed errors, rerun with: -v
==18994== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Aborted
anisha@linux-y3pi:~/Desktop>
Aquarius_Girl
  • 21,790
  • 65
  • 230
  • 411
  • 1
    When a exception is thrown,stack unwinding calls destructors for all the objects ***created*** within that scope(`{`,`}`) It does not destroy objects that is owned. – Alok Save Jun 13 '12 at 09:42
  • If an exception is thrown and never caught then it is *implementation defined* as to whether stack unwinds or `abort()` gets called first, it seems your implementation doesn't unwind the stack and it is allowed as per the standard. – Alok Save Jun 13 '12 at 09:44
  • why do you think the destructor should be called? when throwing an exception, only objects out of whose scope the exceptions is thrown will be destructed. In your case, there are no objects defined only inside the body of `divisionClass::doDivide()`. – Walter Jun 13 '12 at 09:46
  • @Walter `why do you think the destructor should be called? ` Actually, I was studying RAII which says that if you put the methods in a class and destructor will take care of memory freeing with throws happen (w.r.t exception safe code). – Aquarius_Girl Jun 13 '12 at 10:13
  • @AnishaKaul: My first comment under the Q is what is the warranted behavior. – Alok Save Jun 13 '12 at 10:43
  • @Als after reading `Steve Jessop`'s answer I understand your above comment. – Aquarius_Girl Jun 13 '12 at 10:51
  • 1
    @AnishaKaul: This similar Q [here](http://stackoverflow.com/a/9972063/452307) might help you understand better. – Alok Save Jun 13 '12 at 10:55

4 Answers4

3

Throwing an exception from a method does not destroy the object that owns it. Only when it is deleted, or goes out of scope (in this case, at the end of main()) will it be destroyed and the destructor called.

Rook
  • 5,734
  • 3
  • 34
  • 43
3

When you catch an exception, the stack is "unwound" between the point where the exception was thrown, and the point where it is caught. This means that all automatic variables in the scopes between those two points are destroyed -- everything inside the try that corresponds to whatever catch matches the exception.

Your object obj is an automatic variable in the main function, outside the try. Hence, it is not destroyed when the stack is unwound. Your code relies on that fact -- after the first catch you call doDivide on it again, so it better not have been destroyed.

If you don't catch the exception at all, then it is implementation-defined whether or not the stack is unwound (15.3/9 in C++11) before the program is terminated. It looks as though in your second test, without any catch clauses, it is not.

This means that if you want your RAII objects to "work", then you can't allow uncaught exceptions in your program. You could do something like:

int main() {
    try {
        do_all_the_work();
    } catch (...) {
        throw; // or just exit
    }
}

Now you're guaranteed that any automatic variables in do_all_the_work will be destroyed if an exception escapes the function. The downside is that you might get less info out of your debugger, because it has forgotten the original throw site of the uncaught exception.

Of course, it's still possible for code in your program to prevent your obj from being destroyed, for example by calling abort().

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
2

The message is printed in the destructor of divisionClass. You only have one object of that type, that gets destroyed at the end of main.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • so, it means that when the exception is thrown, the destructor isn't called? – Aquarius_Girl Jun 13 '12 at 09:30
  • @AnishaKaul **if** you catch it, no. If you let it propagate (assume you did this in another method called from main, and catch the exception in main), then yes, but that's because the object scope ended. – Luchian Grigore Jun 13 '12 at 09:31
  • @AnishaKaul: Stack unwinding destructs objects(and hence calls destructors) created within that scope in which exception was thrown. – Alok Save Jun 13 '12 at 09:31
  • Luchain, ` If you let it propagate` what does this mean? I'll see what happens if I don't catch the exception. – Aquarius_Girl Jun 13 '12 at 09:33
  • @AnishaKaul means in `main` you catch call another method `foo` with all your logic (minus the `try/catch`). In main you surround `foo` with `try/catch`. – Luchian Grigore Jun 13 '12 at 09:41
  • If you "let the exception propagate", the stack will be unwound and each enclosing scope cleaned up in turn until either a) you run out of enclosing scopes and the program terminates with an error, or b) the exception is caught. In this case, not catching an exception will mean that main() exits before it reaches the end, but you'll still only see the destructor called once because you've still only got a single class instance. – Rook Jun 13 '12 at 09:42
  • `means in main you catch call another method foo with all your logic (minus the try/catch).` Sorry, I didn't get your point. how can I catch the exception without using the try/catch? There is some communication gap- sorry. – Aquarius_Girl Jun 13 '12 at 10:06
  • @AnishaKaul there is a try/catch in main, but not in the function. `void foo() { Object o; throw exception; } int main { try { foo() } catch(...){}}` – Luchian Grigore Jun 13 '12 at 10:18
  • Luchian, thanks for clarifying, that's the way I have written the function in my code above. so, you say that like the way I have let it propogate - the destructor should get called? I have written two exceptions that way but the destructor gets called only once. – Aquarius_Girl Jun 13 '12 at 10:43
  • okay, so which exception call gets the destructor called? the second one ? – Aquarius_Girl Jun 13 '12 at 10:46
  • @AnishaKaul neither. The destructor doesn't get called from an exception. It gets called by closing the scope - `}`. – Luchian Grigore Jun 13 '12 at 10:47
  • @AnishaKaul Neither of the exceptions, the end of main()'s scope does. – jrok Jun 13 '12 at 10:50
  • :( I read RAII which says that if you put the methods in a class and destructor will take care of memory freeing with throws happen (w.r.t exception safe code). Hence the confusion. :( sorry – Aquarius_Girl Jun 13 '12 at 10:50
  • It will, but only if, during stack unwinding, the scope of the objects ends. In your case, the scope `obj` doesn't end, because exceptions *are* handled before that. – jrok Jun 13 '12 at 10:52
  • 1
    @AnishaKaul that is true, but it's not the exception that frees the memory. – Luchian Grigore Jun 13 '12 at 10:52
  • thanks for the clarification and all the follow up comments - Luchain. But, I have to say that your "answer" in current form isn't very much newbie friendly. +1 for your efforts in the comments. – Aquarius_Girl Jun 13 '12 at 10:55
0

Stack unwinding is guaranteed to happen when there's a matching catch handler somewhere up the call stack from the point the exception was thrown. You can simplify and visualize your stack like this:

+-------------------+
| locals            | obj.doDivide()
+-------------------+
|                   | try {}
+-------------------+
| catch { }         |
|                   | main()
| DivisionClass obj |
+-------------------+

Only the part of the stack that's under (in the pic it's above) gets unwound and the corresponding objects are destroyed. The part of the stack with your divisonClass object stays intact until main() exits.

Try this code and see the difference:

void foo()
{
    divisionClass obj;
    obj.doDivide(0);
}

int main()
{
    try {
        foo();
    }
    catch (myExceptionClassA) {
        std::cout << "Check point.\n";
    }
}
jrok
  • 54,456
  • 9
  • 109
  • 141