开发者

Under what circumstances are C++ destructors not going to be called?

开发者 https://www.devze.com 2023-01-05 23:01 出处:网络
I know that my destructors are called on normal unwind of stack and when exceptions are thrown, but not when exit()开发者_C百科 is called.

I know that my destructors are called on normal unwind of stack and when exceptions are thrown, but not when exit()开发者_C百科 is called.

Are there any other cases where my destructors are not going to get called? What about signals such as SIGINT or SIGSEGV? I presume that for SIGSEGV, they are not called, but for SIGNINT they are, how do I know which signals will unwind the stack?

Are there any other circumstances where they will not be called?


Are there any other circumstances where they[destructors] will not be called?

  1. Long jumps: these interfere with the natural stack unwinding process and often lead to undefined behavior in C++.
  2. Premature exits (you already pointed these out, though it's worth noting that throwing while already stack unwinding as a result of an exception being thrown leads to undefined behavior and this is why we should never throw out of dtors)
  3. Throwing from a constructor does not invoke the dtor for a class. This is why, if you allocate multiple memory blocks managed by several different pointers (and not smart pointers) in a ctor, you need to use function-level try blocks or avoid using the initializer list and have a try/catch block in the ctor body (or better yet, just use a smart pointer like scoped_ptr since any member successfully initialized so far in an initializer list will be destroyed even though the class dtor will not be called).
  4. As pointed out, failing to make a dtor virtual when a class is deleted through a base pointer could fail to invoke the subclass dtors (undefined behavior).
  5. Failing to call matching operator delete/delete[] for an operator new/new[] call (undefined behavior - may fail to invoke dtor).
  6. Failing to manually invoke the dtor when using placement new with a custom memory allocator in the deallocate section.
  7. Using functions like memcpy which only copies one memory block to another without invoking copy ctors. mem* functions are deadly in C++ as they bulldoze over the private data of a class, overwrite vtables, etc. The result is typically undefined behavior.
  8. Instantiation of some of smart pointers (auto_ptr) on an incomplete type, see this discussion


The C++ standard says nothing about how specific signals must be handled - many implementations may not support SIGINT, etc. Destructors will not be called if exit() or abort() or terminate() are called.

Edit: I've just had a quick search through the C++ Standard and I can't find anything that specifies how signals interact with object lifetimes - perhaps someone with better standards-fu than me could find something?

Further edit: While answering another question, I found this in the Standard:

On exit from a scope (however accomplished), destructors (12.4) are called for all constructed objects with automatic storage duration (3.7.2) (named objects or temporaries) that are declared in that scope, in the reverse order of their declaration.

So it seems that destructors must be called on receipt of a signal.


Another case they won't be called is if you are using polymorphism and have not made your base destructors virtual.


A signal by itself won't affect the execution of the current thread and hence the invocation of destructors, because it is a different execution context with its own stack, where your objects do not exist. It's like an interrupt: it is handled somewhere outside of your execution context, and, if handled, the control is returned to your program.

Same as with multithreading, C++ the language does not know a notion of signals. These two are completely orthogonal to each other and are specified by two unrelated standards. How they interact is up to the implementation, as long as it does not break either of the standards.

As a side note, another case is when object's destructor won't be called is when its constructor throws an exception. Members' destructors will still be called, though.


abort terminates program without executing destructors for objects of automatic or static storage duration as Standard says. For other situations you should read implementation specific documents.


If a function or method has a throws specification, and throws something NOT covered by the specification, the default behavior is to exit immediately. The stack is not unwound and destructors are not called.

POSIX signals are an operating system specific construct and have no notion of C++ object scope. Generally you can't do anything with a signal except maybe, trap it, set a global flag variable, and then handle it later on in your C++ code after the signal handler exits.

Recent versions of GCC allow you to throw an exception from within synchronous signal handlers, which does result in the expected unwinding and destruction process. This is very operating system and compiler specific, though


A lot of answers here but still incomplete!

I found another case where destructors are not executed. This happens always when the exception is catched across a library boundary.

See more details here:

Destructors not executed (no stack unwinding) when exception is thrown


There are basically two situations, where destructors are called: On stack unwind at the end of function (or at exceptions), if someone (or a reference counter) calls delete.

One special situation is to be found in static objects - they are destructed at the end of the program via at_exit, but this is still the 2nd situation.

Which signal leaves at_exit going through may depend, kill -9 will kill the process immediately, other signals will tell it to exit but how exactly is dependent on the signal callback.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号