Thread: life cycle of exception object

  1. #1
    Registered User
    Join Date
    May 2006
    Posts
    1,579

    life cycle of exception object

    Hello everyone,


    1.

    Suppose I have code like this. According to the standard, the storage of exception object is undefined (could be either on stack or on heap?).

    2.

    I am wondering what is the life cycle of the exception object which reference variable e binded to? For example, could we bind a global reference to the exception object referred by e? Or doing something on the exception object beyond the bracket?

    3.

    The life cycle of variable e itself should not beyond the bracket, right?

    Code:
    catch (exception& e)
    {
        // ...
    }

    thanks in advance,
    George

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    1) The storage of the exception object can be anywhere. Technically, doing "throw x;" where x is some object or value, then x ceases to exist when control passes out of the scope in which it was created. For example;
    Code:
    void f()
    {
          {
               SomeType x;
               throw x;
          }
          //   x does not exist here
    }
    While x ceases to exist as soon as control is returned to an enclosing scope, a temporary copy of x exists until the exception is caught (or the program terminates due to an uncaught exception) -- and will be copied repeatedly as control passes to enclosing scopes. Then compiler implementation details kick in, as the standard explicitly allows (as opposed to "requires") the compiler to avoid creating a temporary if the only way of detecting that temporary is by tracking constructor and destructor calls.

    2) and 3) The reference e exists until control leaves the scope of the catch block, as does the object e refers to. If the catch block rethrows the exception then, logically, a copy of the exception object will be created, and copied during stack unwinding. Practically, again, the compiler is allowed to be smarter than that, so it can avoid creating copies.

  3. #3
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks grumpy,


    Suppose in catch block we pass the address of the exception object to a global pointer variable or make a global reference variable binded to the exception object (let me know if I have not made myself understood). And after catch block or even after function returns, is it safe to access the global reference variable or the global pointer variable?

    Quote Originally Posted by grumpy View Post
    1) The storage of the exception object can be anywhere. Technically, doing "throw x;" where x is some object or value, then x ceases to exist when control passes out of the scope in which it was created. For example;
    Code:
    void f()
    {
          {
               SomeType x;
               throw x;
          }
          //   x does not exist here
    }
    While x ceases to exist as soon as control is returned to an enclosing scope, a temporary copy of x exists until the exception is caught (or the program terminates due to an uncaught exception) -- and will be copied repeatedly as control passes to enclosing scopes. Then compiler implementation details kick in, as the standard explicitly allows (as opposed to "requires") the compiler to avoid creating a temporary if the only way of detecting that temporary is by tracking constructor and destructor calls.

    2) and 3) The reference e exists until control leaves the scope of the catch block, as does the object e refers to. If the catch block rethrows the exception then, logically, a copy of the exception object will be created, and copied during stack unwinding. Practically, again, the compiler is allowed to be smarter than that, so it can avoid creating copies.

    regards,
    George

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    That would equivalent of taking a reference/address of a local variable in any other context, so no, this is not valid and leads to undefined behaviour.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Mats,


    I have written some code which verified that the caught object instance is not the original one we thrown. Looks like we only get a temporary exception object in catch block?

    Here is my code. You can see two object instance is created.

    Code:
    #include <iostream>
    
    using namespace std;
    
    class Foo {
    public:
    	Foo(int input)
    	{
    		this->a = input;
    		cout << this << endl;
    	}
    
    	Foo (const Foo& input)
    	{
    		this->a = input.a;
    		cout << this << endl;
    	}
    	int a;
    };
    
    void foo()
    {
    	try {
    		Foo* f = new Foo (100);
    		throw *f;
    	} catch (const Foo& e)
    	{
    		cout << e.a << endl;
    	}
    }
    
    int main()
    {
    	foo();
    }
    Quote Originally Posted by matsp View Post
    That would equivalent of taking a reference/address of a local variable in any other context, so no, this is not valid and leads to undefined behaviour.

    --
    Mats

    regards,
    George

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Yes, like Grumpy said, it's a temporary copy of the original object - the original object may even be destroyed by the time the catch is entered.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Mats,


    1. In my sample, since I am using new, I thnk it is safe to address the original exception object later, right?

    2. All we are talking about not safe to address exception object is the temporary copied object, right? Not the original one.

    Quote Originally Posted by matsp View Post
    Yes, like Grumpy said, it's a temporary copy of the original object - the original object may even be destroyed by the time the catch is entered.

    --
    Mats

    regards,
    George

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Sure, if you use new to create some object that you then use for throw, the object will not be destroyed as part of the trhow operation - it will be copied, but not destroyed.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks Mats,


    My question is answered. As a conclusion:

    1. There are a temporary copy and the original object instance;
    2. For the original object instance, it follows normal C++ object instance life cycle;
    3. For the temporary copy object instance, it is not safe to address it outside catch block.

    My conclusions are correct? :-)

    Quote Originally Posted by matsp View Post
    Sure, if you use new to create some object that you then use for throw, the object will not be destroyed as part of the trhow operation - it will be copied, but not destroyed.

    --
    Mats

    regards,
    George

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Your conclusions are wholly unnecessary.

    1) They might be the same.
    2) No, it might be merged with the exception object.
    3) Of course not.


    One addition to what grumpy said: a re-throw does not create a new exception object.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Hi CornedBee,


    Can you show me some pseudo code for (1) and (2) please?

    Quote Originally Posted by CornedBee View Post
    Your conclusions are wholly unnecessary.

    1) They might be the same.
    2) No, it might be merged with the exception object.
    3) Of course not.


    One addition to what grumpy said: a re-throw does not create a new exception object.

    regards,
    George

  12. #12
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by George2 View Post
    1. There are a temporary copy and the original object instance;
    Not quite. Logically, the behaviour is as if the original object is copied to enclosing scopes. Practically, the compiler is allowed to avoid creating such temporary objects. In your test case, the compiler has created such a temporary copy.

    A compiler is allowed to avoid creating a temporary if the only way of detecting the existence of that temporary is by tracking constructor and destructor calls (such as you have done).
    Quote Originally Posted by George2 View Post
    2. For the original object instance, it follows normal C++ object instance life cycle;
    Not quite. Practically, if a compiler eliminates temporaries, the object may exist longer than you would expect.


    Quote Originally Posted by George2 View Post
    3. For the temporary copy object instance, it is not safe to address it outside catch block.
    This is true; accessing any object (eg dereferencing a pointer to it) introduces undefined behaviour if the object is not guaranteed to exist. An caught exception object is not guaranteed to exist for any code outside it's catch handler.

    As for your example of throwing a dynamically allocated object......

    If you throw the address of an object, viz;
    Code:
    try
    {
        SomeType *x = new SomeType;
        throw x;
    }
    catch (SomeType *foo)
    {
         // foo will have the same value as x, as the value will be copied to foo
         
         delete foo;
    }
    The only thing that changes in this case is that the "object" thrown is a pointer.

    As an aside, it is not generally a good idea for the creation (or copying) of an exception object to involve dynamic memory allocation; if that memory allocation fails, the exception thrown is not the exception expected. Of, if that failure occurs during stack unwinding, the program will abort().
    Last edited by grumpy; 02-04-2008 at 06:07 AM.

  13. #13
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Can you show me some pseudo code for (1) and (2) please?
    No, it's a compiler optimization.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  14. #14
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Thanks grumpy!


    Great!! Your reply gives me more insights.

    1.

    Quote Originally Posted by grumpy View Post
    A compiler is allowed to avoid creating a temporary if the only way of detecting the existence of that temporary is by tracking constructor and destructor calls (such as you have done).
    Seems confusing. My code shows a temporary object is needed. Seems you mentioned a case when temporary object is not needed -- which is not the same as I have mentioned. You mean compiler optimization to avoid creating a temporary object?

    What do you mean "the only way of detecting the existence of that temporary is by tracking constructor and destructor calls"?

    2.

    Quote Originally Posted by grumpy View Post
    Not quite. Practically, if a compiler eliminates temporaries, the object may exist longer than you would expect.
    You mean if compiler optimize the code and does not generate temporary, and let the exception object in the catch block the same as the one in try block?

    If yes, I still do not know even in this way, why compiler needs to prolong the life cycle of the exception object instance in the try block?


    regards,
    George

  15. #15
    Registered User
    Join Date
    May 2006
    Posts
    1,579
    Hi CornedBee,


    I can understand the exception object in try and in catch may share the same object instance for compiler optimization purpose.

    But what do you mean (2) -- "No, it might be merged with the exception object.". What do you mean merged?

    Quote Originally Posted by CornedBee View Post
    No, it's a compiler optimization.

    regards,
    George

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Telling a shared_ptr not to delete object?
    By TriKri in forum C++ Programming
    Replies: 5
    Last Post: 08-16-2008, 04:26 AM
  2. circular doubly linked list help
    By gunnerz in forum C++ Programming
    Replies: 5
    Last Post: 04-28-2007, 08:38 PM
  3. Problem with the exception class in MINGW
    By indigo0086 in forum C++ Programming
    Replies: 6
    Last Post: 01-20-2007, 01:12 PM
  4. const at the end of a sub routine?
    By Kleid-0 in forum C++ Programming
    Replies: 14
    Last Post: 10-23-2005, 06:44 PM
  5. Life, The Universe, and everything else
    By ZooTrigger1191 in forum A Brief History of Cprogramming.com
    Replies: 7
    Last Post: 03-29-2003, 05:33 PM