"delete this" in constructor
Asked Answered
S

3

31

What actually happen when I execute this code?

class MyClass
{
    MyClass()
    {
        //do something
        delete this;   
    }
}
Sanctum answered 14/3, 2011 at 19:44 Comment(12)
this is real problem, because I need to create something like "zombie thread" which wrapped in a class that will delete itself until the thread is finish executing.Sanctum
If that's what you're looking for, then ask about that, Uray, not this.Mathura
I think it's an interesting question.Eshman
@Rob: if I ask about that, I will never known what the consequences of doing something like this until it become a bug. and my actual implementation of this is not really a problem that I need to ask.Sanctum
Why is this interesting. To me it is self defeating. Even if it was valid (which it can't be) the questions that would erupt if seen be other engineers would be defining to the point of distraction. The ultimate question is why do you think you need this. Your current thread based reason needs more explanation.Nancynandor
@Hans "based on actual problems that you face". I doubt that that is a sensible criterion.Bryophyte
@martin: after I know the implication of this, then I don't need this.Sanctum
@uray: About your "zombie thread" thing I can only recommend not to do it. I have just spent 2 afternoons with such a self-deleting thread class because of a race condition with deleting the thread object as the last thing of the static thread function. It's of course perfectly legitimate to do such a thing, and there's no way it could fail. Except when there are more than 3 threads, it crashes in 1 of 100 cases, now try and debug that :-(Blaze
Please show us a real use case.Typecase
Ok, here's a use case. During a particularly heavy object's construction, the object needs to check the memory pool to see if there is indeed enough memory for it to be instantiated. If there is not enough memory, then object construction should be cancelled (delete this) and the NULL pointer returned from the ctor. Of course, a better way to do this is use a factory method to accomplish this (factory checks if there is enough memory, and only if there is enough memory, proceeds with construction).Unifoliate
@Unifoliate - but constructors don't "return" anything, how can you get it to return NULL? You're probably better off making your constructor exception-safe and throwing an exception instead of delete this. (Are you confusing constructor with call to "new"?)Ornery
Here is another use case since C++20. When you return from a function, local stop_callback object is destructed and the callback function is unregistered(if not called yet). You want the callback still active after returning, so you put the stop_callback object in the heap instead, and write a wrapper callback function which does: one, call the original callback function; and two, delete the stop_callback object. Now imagine if stop_requested() == true when constructing, the wrapper callback function is called right in the stop_callback constructer, deleting the stop_callback object itself.Maxi
R
40

Note: This answer applies to C++03, and it seems like the behavior was changed in C++11 and higher so that this is now undefined behavior.

It turns out that in this particular case the code is legal, but you're ε-away from undefined behavior.

The C++03 standard defines the notion of the "lifetime" of an object to be the time between which its constructor has finished running and when the destructor starts running. It also explicitly states (in §3.8/5) that

Before the lifetime of an object has started [...] If the object will be or was of a class type with a non-trivial destructor, and the pointer is used as the operand of a delete-expression, the program has undefined behavior.

Since an object's lifetime has not started until the constructor finishes, inside the constructor the this pointer you've referred to has not begun its lifetime, trying to delete it in this case is totally safe. However, if you write a destructor for the class, then you'll immediately run into undefined behavior here.

In addition, if you change the constructor so that you try referencing any of the class's data members after you delete the object, you'll get undefined behavior. If the object was allocated on the stack, you'll get undefined behavior. If the object was static, you'll get undefined behavior. If the object was allocated using new, then the pointer the client will get back to it will be invalid and using it will result in undefined behavior. In general, don't try doing this!

Room answered 14/3, 2011 at 19:52 Comment(11)
However the object must already exist as the constructor is called after the initialization list is done, which means that the memory space is allocated and the this pointer is initialized (since you can use *this as an argument in the initializer list).Abohm
@tloach- I think there's a difference between "the pointer has been set up to point to something" and "the object that the pointer points at is fully-constructed." You can have a pointer to unconstructed memory; for example, you can typecast malloc(sizeof(T)) to a T* to get such a pointer. The issue is more that because the object hasn't started its lifetime yet, the behavior of destructing it is undefined.Room
But this type actually doesn't have a non-trivial destructor. Will we get away then? :-)Jellaba
@Bo: heh, I suspect technically still not. If nothing else, it means that whoever called new will use an invalid pointer value (by copying it to something, if only the temporary value that is the result of the new expression). Using a deleted pointer value is UB in the standard, although it doesn't cause anything bad to happen on any implementation I know.Miff
@Bo Persson- Wow, I totally missed that. I'll update the answer right away.Room
I missed that too (in my answer :-) until I read the section you quoted. So it might work, but is really close to the edge. Wonder if all compiler writers get this right...Jellaba
so if I do instantiation as a temporary object, not on the stack, not static, never create the destructor and never inherit it, then it is safe? (and don't try this)Sanctum
No, it's not safe. I should have been more general in saying that this is only safe if every object of this type that you create is allocated on the heap, since otherwise you're deleting non-heap allocated memory, which results in undefined behavior. Writing something like CallFunction(MyClass()) will cause undefined behavior since the temporary MyClass is not allocated via new. However, writing something like CallFunction(new MyClass) is safe as long as you don't try to use the parameter!Room
IMO, it's questionable whether that paragraph applies. Those rules aren't meant to apply for classes under construction. There was an issue report, and C++0x fixed the text to insert "For an object under construction or destruction, see 12.7. Otherwise ..."Bryophyte
The spec says "12.4/14" "the behavior is undefined if the destructor is invoked for an object whose lifetime has ended". I wonder whether it should say "whose lifetime has ended or not yet started" instead. I cannot find any rule that clearly says that the code in the question is invalid, at least. Even with an own constructor defined.Bryophyte
I agree with @JohannesSchaub-litb. That sentence cannot be meant to apply to classes under construction. Because later in the standard it says it is also UB if "the pointer is used to access a non-static data member or call a non-static member function of the object", which is known to be OK to do in a constructor.Maxi
B
1

The first thing that I want to understand here is WHY do you want to do something like this?

Constructor is a member function where your object is actually getting constructed and you can delele an object once it is fully constructed, that's why doing somrthing like this -

class A
{
public:
    A()
    {
        delete this;
    }

    ~A()
    {
    }
};

results in an undefined behavior.

Also, to add to this, if you perform delete this in the destructor, it is also not correct since the object is itself undergoing the destruction and doing delete this in the destructor will again call the destructor.

class A
{
public:
    A()
    {
    }

    ~A()
    {
        delete this;   // calls the destructor again. 
    }
};
Bonanza answered 25/8, 2018 at 6:42 Comment(0)
A
-1

Assuming your object is never inherited by anything this should work fine. Your constructor runs and then the destructor is immediately called. If anything inherits this object it will break since this constructor will be called before the inheriting constructor.

Abohm answered 14/3, 2011 at 19:51 Comment(4)
Will the constructor "finish" before the destructor is called? Does calling a destructor (implicitly via delete) inside the constructor cause UB?Hove
@tloach- I could be wrong, but I believe that this results in undefined behavior (see my answer). If I'm incorrect, please let me know and I'll remove my downvote.Room
how to make a class that couldn't be inherited then?Sanctum
@Sanctum Make the constructor private.Pants

© 2022 - 2024 — McMap. All rights reserved.