Suppose I have a class whose constructor spawns a thread that deletes the object:
class foo {
public:
foo()
: // initialize other data-members
, t(std::bind(&foo::self_destruct, this))
{}
private:
// other data-members
std::thread t;
// no more data-members declared after this
void self_destruct() {
// do some work, possibly involving other data-members
delete this;
}
};
The problem here is that the destructor might get invoked before the constructor has finished. Is this legal in this case? Since t is declared (and thus initialized) last, and there is no code in the constructor body, and I never intend to subclass this class, I assume that the object has been completely initialized when self_destruct is called. Is this assumption correct?
I know that the statement delete this; is legal in member-functions if this is not used after that statement. But constructors are special in several ways, so I am not sure if this works.
Also, if it is illegal, I am not sure how to work around it, other spawning the thread in a special initialization-function that must be called after construction of the object, which I really would like to avoid.
P.S.: I am looking for an answer for C++03 (I am restricted to an older compiler for this project). The std::thread in the example is just for illustration-purposes.
Firstly, we see that an object of type
foohas non-trivial initialization because its constructor is non-trivial (§3.8/1):Now we see that an object of type
foo‘s lifetime begins after the constructor ends (§3.8/1):Now, it is undefined behaviour if you do
deleteon the object before the end of the constructor if the typefoohas a non-trivial destructor (§3.8/5):So since our object is under construction, we take a look at §12.7:
That means that it’s fine for
self_destructto be called while the object is being constructed. However, this section says nothing specifically about destroying an object while it is being constructed. So I suggest we look at the operation of thedelete-expression.First, it "will invoke the destructor (if any) for the object […] being deleted." The destructor is a special case of member function, so it is fine to call it. However, §12.4 Destructors says nothing about whether it is well-defined when the destructor is called during construction. No luck here.
Second, "the delete-expression will call a deallocation function" and "the deallocation function shall deallocate the storage referenced by the pointer". Once again, nothing is said about doing this to storage that is currently being used be an object under construction.
So I argue that this is undefined behaviour by the fact that the standard hasn’t defined it very precisely.
Just to note: the lifetime of an object of type
fooends when the destructor call starts, because it has a non-trivial destructor. So ifdelete this;occurs before the end of the object’s construction, its lifetime ends before it starts. This is playing with fire.