31

What actually happen when I execute this code?

class MyClass
{
    MyClass()
    {
        //do something
        delete this;   
    }
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
uray
  • 11,254
  • 13
  • 54
  • 74
  • 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. – uray Mar 14 '11 at 20:01
  • 4
    If that's what you're looking for, then ask about *that*, Uray, not *this*. – Rob Kennedy Mar 14 '11 at 20:21
  • 11
    I think it's an interesting question. – James McNellis Mar 14 '11 at 20:22
  • @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. – uray Mar 14 '11 at 20:40
  • 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. – Martin York Mar 14 '11 at 21:48
  • 3
    @Hans "based on actual problems that you face". I doubt that that is a sensible criterion. – Johannes Schaub - litb Mar 14 '11 at 22:17
  • @martin: after I know the implication of this, then I don't need this. – uray Mar 15 '11 at 14:09
  • @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 :-( – Damon Aug 02 '11 at 20:24
  • Please show us a real use case. – curiousguy Oct 26 '11 at 20:35
  • 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). – bobobobo Sep 03 '13 at 02:32
  • @bobobobo - 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"?) – Steve Folly May 25 '14 at 10:01
  • 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. – zwhconst Feb 27 '22 at 07:03

3 Answers3

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!

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 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). – tloach Mar 14 '11 at 20:03
  • @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. – templatetypedef Mar 14 '11 at 20:06
  • But this type actually doesn't have a non-trivial destructor. Will we get away then? :-) – Bo Persson Mar 14 '11 at 20:11
  • @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. – Steve Jessop Mar 14 '11 at 20:15
  • @Bo Persson- Wow, I totally missed that. I'll update the answer right away. – templatetypedef Mar 14 '11 at 20:16
  • 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... – Bo Persson Mar 14 '11 at 20:25
  • 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) – uray Mar 14 '11 at 20:48
  • 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! – templatetypedef Mar 14 '11 at 20:50
  • 2
    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 ..." – Johannes Schaub - litb Mar 14 '11 at 22:21
  • 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. – Johannes Schaub - litb Mar 14 '11 at 22:36
  • 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. – zwhconst May 12 '23 at 10:32
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. 
    }
};
Aman Gupta
  • 360
  • 2
  • 9
-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.

tloach
  • 8,009
  • 1
  • 33
  • 44