Consider the following piece of code for C++:
class A {
A() {
if(some condition)
exit(1);
}
};
Is this legitimate to do? i.e. exiting directly from a constructor before it has completed. Are there any side effects to this?
Yes, this is legal C++. However, be aware that this doesn't unwind the stack like a call to throw; would do, so the destructors of any stack-allocated variables will not be called. But it will call the destructor of static variables. See the documentation of std::exit() for more information.
Is this legitimate to do?
Technically yes. That said, I cannot think of a reasonable use case.
Are there any side effects to this?
exit has effect of terminating the process (static objects are destroyed; automatic objects are not). Calling it within a constructor doesn't change that.
There are different points of view:
Is it correct code from a compiler point of view?
Yes. The exit function can be called at any point from a C++ program and will cause the program to exit as soon as possible.
Are there possible unexpected side effects?
Yes. The destructors of any members or base classes of the object under construction will not be called. For example if some of them were responsible for writing data on disk that should be used on next start, that data might not be written.
Is there any case where it is legitimate code?
No. If you need to abort inside an object constructor, you should throw an exception. If the exception is not caught, it will indeed abort the program, but in a clean way, ensuring that any constructed objects (even members of the object in construction) will have its destructor called. And any caller will have an opportunity to do some clean up.
Long story made short: NEVER DO THAT!
Related
I'm trying to validate my understanding of C++ destructors.
I've read many times that C++ supplies a default destructor if I don't write one myself. But does this mean that if I DO write a destructor that the compiler WON'T still provide the default cleanup of stack-allocated class fields?
My hunch is that the only sane behavior would be that all class fields are destroyed no matter what, whether I provide my own destructor or not. In which case the statement I've read so many times is actually a little misleading and could be better stated as:
"Whether or not you write your own destructor, the C++ compiler always
writes a default destructor-like sequence to deallocate the member
variables of your class. You may then specify additional
deallocations or other tasks as needed by defining your own destructor"
Is this correct?
When an object is cleaned up in C++, the language will
First call the destructor for the class, then
Call the destructors for all the fields of the class.
(This assumes no inheritance; if there's inheritance, the base class is then destroyed by recursively following this same procedure). Consequently, the destructor code that you write is just custom cleanup code that you'd like to do in addition to the normal cleanup code for individual data members. You won't somehow "lose" the destructors for those objects being called as normal.
Hope this helps!
Yes -- any object contained within your object will be destroyed as part of destroying your object, even if/though your destructor does nothing to destroy them.
In fact, your destructor won't normally do anything to destroy objects contained within the object; what it typically does is destroy objects that are remotely owned via something in the object (e.g., a pointer to an object, a handle to a network or database connection, etc.)
The only exception to this that's common at all is if your object contains a buffer of some sort, and you've used placement new to construct something into that buffer. If you use placement new, you normally plan on directly invoking the dtor as well. [Note that "common" is probably overstating how often you see/use this--it's really quite uncommon, but the other possibilities are much rarer still.]
Yes. Even if you DO write a destructor, the C++ compiler will create a sequence. Consider the following code:
class foo{
int a;
}
Write a destructor that deallocates a, a stack-allocated variable... its impossible. Therefore, even if you write your own destructor, a C++ compiler MUST generate one to deallocate stack objects.
Hi I found this line in a tutorial on web.
What happens when you declare a static object and the destructor throws and exception?
As with static constructor exceptions the application will crash.
I can't seam to understand what's the difference if object is static or not...
Thanks
I'm not sure if you're asking about constructors or destructors that throw exceptions - the problem statement refers to destructors, but the example code and some of the comments refer to constructors.
With regards to constructors that throw, it depends on whether the static object is local or global. Local static objects are constructed the first time that control passes through the scope in which they are defined, and exception handlers should behave normally for them. Global static objects are constructed before the program enters main(); since you can't have a try-catch block at global scope, if the constructor of a global static object throws, it basically means that your application crashes before it makes it out of the starting gate.
As for destructors, generally speaking, destructors that can throw exceptions create serious problems. Herb Sutter details the reasons why in his great book "Exceptional C++", which is available here on Google Books. Basically, if a destructor can throw exceptions, it makes it nearly impossible to write exception-safe code. Consider the following example.
class T
{
T() {}
~T() { throw 5; }
};
void foo()
{
T t;
throw 10;
}
When foo() reaches the throw 10; statement, control will exit the context of foo(), destroying the local object t in the process. This calls the destructor for t, which tries to throw another exception. In C++, it isn't possible to throw two exceptions simultaneously; if a second exception is thrown like this, the program calls the built-in function terminate(), which does what it sounds like and terminates the program (you can set your own function to be called instead using set_terminate, but this is mostly for doing custom clean-up - you can't change the fact that the program ends after the function is done).
The way to avoid this is to make sure that destructors never throw exceptions. It may not matter with static objects, because as celtschk noted the destructor won't be called until the program is terminating anyway, but as a general rule, if you find yourself writing a class with a destructor that can throw an exception, you should think carefully about whether it is really the best approach.
As I know, std::string is a RAII object so I don't need to initialize after declaration. The constructor will take care of this stuff automatically. But is there any exception on any platform or any compiler ?
class TestString
{
public:
TestString()
{
// m_str.clear(); or
// m_str = "";
}
virtual ~TestString(){}
private:
std::string m_str;
};
Very simple question, thanks !
The default constructor for std::string constructs an empty string, with a length of zero characters. That is the guarantee offered by the default constructor on all platforms for all implementations.
In C++, initialisation may involve several method calls after construction, but this doesn't violate RAII. It's the constructors responsibility to get the object into a self-consistent valid state - in particular, one where it's safe to call the destructor or any other method. Depending on your requirements, this may mean nothing more than setting some variables to zero.
So why the big fuss about RAII? Well, the original point of RAII (Resource Allocation Is Initialisation) related to exception safety.
When a function exits early, in particular due to an exception throw, it's important that destructors are called - that resources (heap memory and file handles, for example) are released. C++ mandates that destructor calls occur automatically when a variable goes out of scope for that reason. However, an exception throw can happen at any time, at least in principle. How can you be sure that the resource you want to release has even been allocated? If your not sure that that allocation will have been done you could use a flag or a null handle or similar so you can test in the destructor, but how can you be sure that flag has been initialised?
Basically, in order to be able to call a destructor safely, C++ needs to know that the object has been initialised. That is handled by the constructor. But that just leads to another subtle issue - what happens if an exception throw occurs inside the constructor.
Long story short - C++ takes responsibility for the destructor call only after the constructor has successfully completed. If the constructor is exited early by an exception throw, there will be no destructor call - if exceptions haven't been handled carefully (or proven impossible) within the constructor, memory and/or resource leaks may occur.
Anyway, the origin of the name is simply that resources aren't considered to have been acquired unless the constructor has completed, therefore freeing resources (by calling the destructor) should occur if and only if the constructor completed successfully.
That's a simple model, though, and the name can be misleading. In practice, resources can be acquired by any method, and the language has no fixed ideas about which kinds of activity are initialisation and which aren't. The important thing is that, if an exception is thrown at an awkward moment and your objects destructor is called as a result, it should always be able to determine exactly what cleanup is needed - which resources to release.
Constructing an object in a self-consistent state isn't a difficult job - it may require no more than setting some member variables to zero. In fact some people strongly recommend that you do no more than this in most classes, the reason being that setting a few POD member variables to zero cannot trigger an exception throw - you don't have to worry about catching and rethrowing exceptions and cleaning up that semi-constructed object.
Every standard library class that has a destructor will meet that self-consistent state requirement. Only "Plain Old Data" types (e.g. int) which by definition don't have destructors (well, no useful destructors at least) don't implement RAII, at least not for themselves.
I know that my destructors are called on normal unwind of stack and when exceptions are thrown, but not when exit() 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?
Long jumps: these interfere with the natural stack unwinding process and often lead to undefined behavior in C++.
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)
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).
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).
Failing to call matching operator delete/delete[] for an operator new/new[] call (undefined behavior - may fail to invoke dtor).
Failing to manually invoke the dtor when using placement new with a custom memory allocator in the deallocate section.
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.
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.
As mentioned in this answer simply calling the destructor for the second time is already undefined behavior 12.4/14(3.8).
For example:
class Class {
public:
~Class() {}
};
// somewhere in code:
{
Class* object = new Class();
object->~Class();
delete object; // UB because at this point the destructor call is attempted again
}
In this example the class is designed in such a way that the destructor could be called multiple times - no things like double-deletion can happen. The memory is still allocated at the point where delete is called - the first destructor call doesn't call the ::operator delete() to release memory.
For example, in Visual C++ 9 the above code looks working. Even C++ definition of UB doesn't directly prohibit things qualified as UB from working. So for the code above to break some implementation and/or platform specifics are required.
Why exactly would the above code break and under what conditions?
I think your question aims at the rationale behind the standard. Think about it the other way around:
Defining the behavior of calling a destructor twice creates work, possibly a lot of work.
Your example only shows that in some trivial cases it wouldn't be a problem to call the destructor twice. That's true but not very interesting.
You did not give a convincing use-case (and I doubt you can) when calling the destructor twice is in any way a good idea / makes code easier / makes the language more powerful / cleans up semantics / or anything else.
So why again should this not cause undefined behavior?
The reason for the formulation in the standard is most probably that everything else would be vastly more complicated: it’d have to define when exactly double-deleting is possible (or the other way round) – i.e. either with a trivial destructor or with a destructor whose side-effect can be discarded.
On the other hand, there’s no benefit for this behaviour. In practice, you cannot profit from it because you can’t know in general whether a class destructor fits the above criteria or not. No general-purpose code could rely on this. It would be very easy to introduce bugs that way. And finally, how does it help? It just makes it possible to write sloppy code that doesn’t track life-time of its objects – under-specified code, in other words. Why should the standard support this?
Will existing compilers/runtimes break your particular code? Probably not – unless they have special run-time checks to prevent illegal access (to prevent what looks like malicious code, or simply leak protection).
The object no longer exists after you call the destructor.
So if you call it again, you're calling a method on an object that doesn't exist.
Why would this ever be defined behavior? The compiler may choose to zero out the memory of an object which has been destructed, for debugging/security/some reason, or recycle its memory with another object as an optimisation, or whatever. The implementation can do as it pleases. Calling the destructor again is essentially calling a method on arbitrary raw memory - a Bad Idea (tm).
When you use the facilities of C++ to create and destroy your objects, you agree to use its object model, however it's implemented.
Some implementations may be more sensitive than others. For example, an interactive interpreted environment or a debugger might try harder to be introspective. That might even include specifically alerting you to double destruction.
Some objects are more complicated than others. For example, virtual destructors with virtual base classes can be a bit hairy. The dynamic type of an object changes over the execution of a sequence of virtual destructors, if I recall correctly. That could easily lead to invalid state at the end.
It's easy enough to declare properly named functions to use instead of abusing the constructor and destructor. Object-oriented straight C is still possible in C++, and may be the right tool for some job… in any case, the destructor isn't the right construct for every destruction-related task.
Destructors are not regular functions. Calling one doesn't call one function, it calls many functions. Its the magic of destructors. While you have provided a trivial destructor with the sole intent of making it hard to show how it might break, you have failed to demonstrate what the other functions that get called do. And neither does the standard. Its in those functions that things can potentially fall apart.
As a trivial example, lets say the compiler inserts code to track object lifetimes for debugging purposes. The constructor [which is also a magic function that does all sorts of things you didn't ask it to] stores some data somewhere that says "Here I am." Before the destructor is called, it changes that data to say "There I go". After the destructor is called, it gets rid of the information it used to find that data. So the next time you call the destructor, you end up with an access violation.
You could probably also come up with examples that involve virtual tables, but your sample code didn't include any virtual functions so that would be cheating.
The following Class will crash in Windows on my machine if you'll call destructor twice:
class Class {
public:
Class()
{
x = new int;
}
~Class()
{
delete x;
x = (int*)0xbaadf00d;
}
int* x;
};
I can imagine an implementation when it will crash with trivial destructor. For instance, such implementation could remove destructed objects from physical memory and any access to them will lead to some hardware fault. Looks like Visual C++ is not one of such sort of implementations, but who knows.
Standard 12.4/14
Once a destructor is invoked for an
object, the object no longer exists;
the behavior is undefined if the
destructor is invoked for an object
whose lifetime has ended (3.8).
I think this section refers to invoking the destructor via delete. In other words: The gist of this paragraph is that "deleting an object twice is undefined behavior". So that's why your code example works fine.
Nevertheless, this question is rather academic. Destructors are meant to be invoked via delete (apart from the exception of objects allocated via placement-new as sharptooth correctly observed). If you want to share code between a destructor and second function, simply extract the code to a separate function and call that from your destructor.
Since what you're really asking for is a plausible implementation in which your code would fail, suppose that your implementation provides a helpful debugging mode, in which it tracks all memory allocations and all calls to constructors and destructors. So after the explicit destructor call, it sets a flag to say that the object has been destructed. delete checks this flag and halts the program when it detects the evidence of a bug in your code.
To make your code "work" as you intended, this debugging implementation would have to special-case your do-nothing destructor, and skip setting that flag. That is, it would have to assume that you're deliberately destroying twice because (you think) the destructor does nothing, as opposed to assuming that you're accidentally destroying twice, but failed to spot the bug because the destructor happens to do nothing. Either you're careless or you're a rebel, and there's more mileage in debug implementations helping out people who are careless than there is in pandering to rebels ;-)
One important example of an implementation which could break:
A conforming C++ implementation can support Garbage Collection. This has been a longstanding design goal. A GC may assume that an object can be GC'ed immediately when its dtor is run. Thus each dtor call will update its internal GC bookkeeping. The second time the dtor is called for the same pointer, the GC data structures might very well become corrupted.
By definition, the destructor 'destroys' the object and destroy an object twice makes no sense.
Your example works but its difficult that works generally
I guess it's been classified as undefined because most double deletes are dangerous and the standards committee didn't want to add an exception to the standard for the relatively few cases where they don't have to be.
As for where your code could break; you might find your code breaks in debug builds on some compilers; many compilers treat UB as 'do the thing that wouldn't impact on performance for well defined behaviour' in release mode and 'insert checks to detect bad behaviour' in debug builds.
Basically, as already pointed out, calling the destructor a second time will fail for any class destructor that performs work.
It's undefined behavior because the standard made it clear what a destructor is used for, and didn't decide what should happen if you use it incorrectly. Undefined behavior doesn't necessarily mean "crashy smashy," it just means the standard didn't define it so it's left up to the implementation.
While I'm not too fluent in C++, my gut tells me that the implementation is welcome to either treat the destructor as just another member function, or to actually destroy the object when the destructor is called. So it might break in some implementations but maybe it won't in others. Who knows, it's undefined (look out for demons flying out your nose if you try).
It is undefined because if it weren't, every implementation would have to bookmark via some metadata whether an object is still alive or not. You would have to pay that cost for every single object which goes against basic C++ design rules.
The reason is because your class might be for example a reference counted smart pointer. So the destructor decrements the reference counter. Once that counter hits 0 the actual object should be cleaned up.
But if you call the destructor twice then the count will be messed up.
Same idea for other situations too. Maybe the destructor writes 0s to a piece of memory and then deallocates it (so you don't accidentally leave a user's password in memory). If you try to write to that memory again - after it has been deallocated - you will get an access violation.
It just makes sense for objects to be constructed once and destructed once.
The reason is that, in absence of that rule, your programs would become less strict. Being more strict--even when it's not enforced at compile-time--is good, because, in return, you gain more predictability of how program will behave. This is especially important when the source code of classes is not under your control.
A lot of concepts: RAII, smart pointers, and just generic allocation/freeing of memory rely on this rule. The amount of times the destructor will be called (one) is essential for them. So the documentation for such things usually promises: "Use our classes according to C++ language rules, and they will work correctly!"
If there wasn't such a rule, it would state as "Use our classes according to C++ lanugage rules, and yes, don't call its destructor twice, then they will work correctly." A lot of specifications would sound that way.
The concept is just too important for the language in order to skip it in the standard document.
This is the reason. Not anything related to binary internals (which are described in Potatoswatter's answer).