Jump to content
  • Advertisement
Sign in to follow this  
Trillian

[C++] 10-seconds exceptions question

This topic is 4016 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello! I have a quick question that I haven't been able to google away, are destructors called if an exception is thrown in the constructor of an object? Sorry if it's been asked, I couldn't find the answer.

Share this post


Link to post
Share on other sites
Advertisement
depends on how/if you handle the exception. if you handle the exception such that normal program control flow continues and your code that calls the destructor or the closing scope triggers that call, then yet it will be called. However, if the exception crashes the program then that crash it's impossible for anything else to be called, destructor or otherwise since your program stops executing as soon as it crashes.

if your question is: will memory be returned to my operating system or do i have to reboot in order to get the memory back the answer is: the operating system will clean up all the memory and return it to the system. that's what protected mode is all about.

-me

Share this post


Link to post
Share on other sites
Er, the destructor is only called for fully-constructed objects, and if an object has not finished the execution of its constructor(s), it is not fully-constructed. It will never have its destructor called, regardless of how you attempt to handle the thrown exception -- the object never came into being, it can not be destroyed.

Share this post


Link to post
Share on other sites
@jpetrie Thanks a lot! It makes sense.

@Palidine Thanks for trying to help but your answer doesn't seem to make any sense. From what I've understood, if an exception is thrown in a constructor (and isn't handled in it) then the new call will not return the object and, for the program, it'll be like the object never existed. So it doesn't seem possible that the "closing scope triggers that [destructor] call". Unless there's something I haven't understood properly?

@SiCrane Thanks for the additional info

Share this post


Link to post
Share on other sites
@summaky I've had a look at it :

Quote:
Original code on C++ Lite FAQ
// A call to

Fred* p = new Fred();

// is equivalent to :

Fred* p = (Fred*) operator new(sizeof(Fred));
try {
new(p) Fred(); // Placement new
}
catch (...) {
operator delete(p); // Deallocate the memory
throw; // Re-throw the exception
}


If I understand well, the "operator delete" used in that catch block is like free() and does NOT call the destructor?

Share this post


Link to post
Share on other sites
Quote:
Original post by Trillian
@summaky I've had a look at it :

Quote:
Original code on C++ Lite FAQ
// A call to

Fred* p = new Fred();

// is equivalent to :

Fred* p = (Fred*) operator new(sizeof(Fred));
try {
new(p) Fred(); // Placement new
}
catch (...) {
operator delete(p); // Deallocate the memory
throw; // Re-throw the exception
}


If I understand well, the "operator delete" used in that catch block is like free() and does NOT call the destructor?


Correct.

However, destructors *are* called for members and bases constructed to date. BUT, that doesn't help you if you're making dynamic allocations:


struct Evil {
static int instances;
Evil() { if (instances++) { throw "up"; } }
};
static int Evil::instances = 0;

struct Bad {
Evil* a;
Evil b;
Bad() : a(new Evil()), b() {}
}

int main() {
Bad bad;
// after bad.b is allocated, its constructor throws. 'bad' is not destructed
// because it never existed. 'b' is not destructed because it never existed.
// 'a' is destructed, but that "calls a destructor" for the *pointer*, so
// the allocated Evil instance leaks.
}


(Similarly, if both members were pointers, and Evil were not so evil, but the dynamic allocation of 'b' *happened* to fail - throwing std::bad_alloc - then, again, allocation of 'b' didn't happen (because of the throw), but 'a' still leaks.)

This means, in practice, that we shouldn't do raw 'new' calls in an initialization list. Instead, use smart pointers - and when implementing such smart pointers (assuming you can't find one that suits your needs), be careful. :)

You might also want to see this thread.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!