This question already has answers here:
Is "delete this" allowed in C++?
(10 answers)
Closed 7 years ago.
Suppose I have a class foo with a function release that calls delete this:
struct foo
{
std::int32_t release() const
{
delete this;
return 0;
}
};
Why can I even call delete this given that the function is const?
Is the behaviour on returning 0 defined? Doesn't the function "sort-of-die" after the delete?
An answer referencing the standard (so I can put a fancy comment in my code) would be much appreciated.
Why can I even call delete this given that the function is const?
From the standard, 5.3.5$2 Delete [expr.delete]
[ Note: a pointer to a const type can be the operand of a
delete-expression; it is not necessary to cast away the constness
(5.2.11) of the pointer expression before it is used as the operand of
the delete-expression. —end note ]
and
Is the behaviour on returning 0 defined?
I think it's safe. delete this; will call the destructor and free the memory hold by the object (including the member variables and base class subobject). After that, if you don't derefrence this, or access any member variables, it'll be safe.
Why can I even call delete this given that the function is const
Because delete doesn't necessarily modify the deleted pointer.
Is the behaviour on returning 0 defined? Doesn't the function "sort-of-die" after the delete?
Why would it? The logic isn't removed from the program. The functionality stays in memory for next objects to use it. It's only this pointer that gets invalidated.
There's an SO answer that points to The ISO C++ FAQ which has an entry on that, excerpts of which:
You must be absolutely 100% positively sure that the rest of your member function (after the delete this line) doesn’t touch any piece of this object (including calling any other member functions or touching any data members). This includes code that will run in destructors for any objects allocated on the stack that are still alive.
You must be absolutely 100% positively sure that no one even touches the this pointer itself after the delete this line. In other words, you must not examine it, compare it with another pointer, compare it with nullptr, print it, cast it, do anything with it.
Since your code abides those rules, again, it's fine.
Related
This question comes from me trying to understand the motivation for smart pointers where you make a wrapper class around the pointer so that you could add a custom destructor. Do pointers (and ints, bools, doubles, etc.) not have a destructor?
Technically speaking, non-class types (C++ term for what often called 'primitive type' in layman words) do not have destructors.
C++ Standard only speaks of real destructors in context of classes, see [class.dtor] in C++ standard. Aside from that, C++ also allows to call a destructor on a non-class object using the same notation, i.e. following code is valid:
void foo(int z) {
using T = int;
z.~T();
}
This is called 'pseudo-destructor' and exists exclusively to allow writing generic templated code to deal in the same manner with class and non-class types. This call does nothing at all. This syntax is defined in [expr.prim.id] in C++ standard.
Primitive types (and compounds thereof) have trivial destructors. These don't do anything, and have special wording that allows them to be skipped altogether in some cases.
This, however, is orthogonal to why C++ has smart pointers. A raw pointer is non-owning: it points at another object, but does not affect its lifetime. Smart pointers, on the other hand, own (or share ownership of) their pointee, tying its lifetime to their own. This is what is implemented inside, among other special functions, their destructor.
In addition to the answers given here so far, since C++20 the pseudo-destructor call on a non-class object will always end its lifetime. Consequently accessing the object's value after the call will have undefined behavior. This does not mean however that the compiler has to emit any code for such a call. It still effectively does nothing.
No, pointers don't have destructors. An object referenced through a plain old pointer has to be deleted to avoid memory leaks, and the object's destructor is called then, but the compiler won't call delete automatically, even when a pointer goes out of scope - what if another part of your program also had a pointer to the same object?
Smart pointers aren't about calling a custom destructor, they're about ensuring that things get cleaned up automatically when they go out of scope. This 'cleaning up' might be deleting owned objects, freeing any malloced memory, closing files, releasing locks, etc.
Destructors are used to free the resources that an object may have used.
For pointers, you don't need delete if you are not allocating new memory from the heap.
C and C++ have two ways to store a variable: stack and heap.
Stack is for static memory, and the compiler takes care of that. Heap is for dynamic memory, and you have to take care of this if you are using it.
When you do primitive type declarations, stack memory is allocated for the variables.
When you use new to declare an object, this object is stored on the heap, which you need to delete it when you are finishing using it, or it would be a memory leak.
Basically, you only need delete if you new something.
This question already has answers here:
Is it legal C++ to test the this-pointer in a member function?
(5 answers)
Closed 6 years ago.
So i'm aware that this is a reference to the class itself, however I can't really tell what it does in an if statement
What does the following code do?
if(this)
{
//Code goes here...
}
I'm fairly sure it is checking if the class is not null, but a further explanation would be great!
this pointer is a constant pointer that holds the memory address of the current object. So, technically this will check whether it is null or not which will not be null in member function. Since you will not be able to call a class until you have its object and in abstract classes you can't use this anyway. So, this if doesn't make much sense.
It's attempting to check to see if the method was called on a NULL pointer, e.g. something like this:
Foo * foo = NULL;
foo->TheMethod();
However, that isn't a valid technique, since calling a method (even a non-virtual method!) on a NULL pointer is undefined behavior and so the test won't work reliably.
It is indeed checking if this != nullptr. However by the time you reach this statement, you have already passed from undefined behavior. Because this is available only in a class method and calling such method with nullptr is UB.
Hence such statement never serves any valid purpose.
Besides UB, also remember that such checks are useful only when called with a pointer. They are irrelevant for object/reference. If the method is virtual then most of the architecture would crash the code before reaching that if.
This question already has answers here:
What will happen when I call a member function on a NULL object pointer? [duplicate]
(6 answers)
When does invoking a member function on a null instance result in undefined behavior?
(2 answers)
Closed 9 years ago.
Inside a constructor, calling non-virtual member functions is permitted.
Does from this fact follow that the following piece of code is well-defined?
struct A {
void foo { std::cout << "Hi there! My address is: " << this; }
};
A * a = nullptr;
a->foo ();
Answer?
With the help of some links given in the comments, and the links given in the linked pages, I now think that the answer can be found e.g. in
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3035.pdf
§3.8 par. 5, p. 66:
"Before the lifetime of an object has started but after the storage which the object will occupy has been allocated ... [t]he program has undefined behavior
if [...] the pointer is used to access a non-static data member or call a non-static member function of the object"
Then it should be even more undefined to call a member function if storage has not been allocated at all.
I guess one important reason why it is a good idea to make it undefined is explained here: https://stackoverflow.com/a/3257755/1419315
That code is undefined behavior.
Note that inside the constructor you can also call virtual member function.
The somewhat tricky part is calling virtual member function during member initialization before the constructor code begins. Still valid but it's not obvious what happens (the point is that until the constructor code begins the object isn't considered yet an instance of its class and virtual member functions get dispatched to the base class).
Some compilers emit a warning if you use this in the member initialization list exactly because the this pointer will behave strangely at that point (it will start behave normally only after the start of the constructor).
The code apparently works because most compilers use the VMT approach for method dispatching but the VMT is not needed to call a non-virtual method and thus if the method code doesn't dereference in any way this then things seems to "work". However the fact that the code seems to work in an implementation (or even in every implementation for that matter) still doesn't make it legal C++ code.
This question already has answers here:
Is it legal/well-defined C++ to call a non-static method that doesn't access members through a null pointer?
(5 answers)
When does invoking a member function on a null instance result in undefined behavior?
(2 answers)
Closed 8 years ago.
Can I call a non-static, non-virtual method of a class from a null pointer? The member function would then test if this==nullptr, and return immediately if it's true.
I know it will work in most cases, but is this a guaranteed result? That way, I can ensure null pointer exceptions never happen, and avoid testing for null pointers in many places of the caller code. That's for compactness, I'm not going to do that right now, but I'm curious to know if any standard will guarantee this to work...
Thanks!
Dereferencing a nullptr is Undefined behavior. Period!
Whether it works or not on one particular implementation is irrelevant, the behavior is not guaranteed.
The standard expliticly mentions dereferencing NULL pointer as undefined behavior. Using opearator -> dereferences the pointer to left.
So you're okay only in case if your implementation defined some behavior for the case, as it is a possibility (though I never encountered it in real life yet).
(I hope you understand that observing something is not the same as being defined.)
always avoid calling a null pointer,
you would usually end up with a core dump
There are interesting answers here:
When does invoking a member function on a null instance result in undefined behavior?
Also, the standard gives no hint about the mechanism for calling member virtual functions. It is usually done by just passing 'this' as a hidden function argument, which will in practice not dereference the pointer and work. However, it seems possible to implement even non-virtual function with a vtable, which in this case would crash.
Interestingly, a Microsoft function relies on this behavior :)
http://msdn.microsoft.com/en-us/library/d64ehwhz%28v=vs.80%29.aspx
This article on Binary-compatible C++ Interfaces contains the code:
class Window {
public:
// ...
virtual void destroy() = 0;
void operator delete(void* p) {
if (p) {
Window* w = static_cast<Window*>(p);
w->destroy(); // VERY BAD IDEA
}
}
};
To me, that seems wrong: operator delete() works on raw memory with the intended purpose to free it. The object's destructor has already been called, so calling destroy() works on a "phantom" object (if it works at all). Indeed: that's why operator delete() takes a void* and not a Window* (in this case).
So, the design is flawed, right? (If it is correct, why is it correct?)
I agree (assuming Window::destroy is not a static member function):
3.8p1: The lifetime of an object of type T ends when: if T is a class type with a non-trivial destructor, the destructor call starts, or [...]
3.8p5: [...] After the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that refers to the storage location where the object [...] was located may be used but only in limited ways. ... If the object will be or was of a non-POD class type, the program has undefined behavior if: the pointer is used to access a non-static data member or call a non-static member function of the object, or [...]
(emphasis mine)
Yes, that code (if labelled C++) is very wrong.
Operator new and delete as you say handle raw memory, not objects.
That article however deals with specific compilers and specific implementation issues so may be that in that restricted context the code works... moreover MS isn't exactly well renowned for how nicely they care about portable C++ (au contraire, indeed) so may be that kind of bad code is (or was in 2002) actually not only working but even a reasonable solution.
That is really nasty code, trying to be helpful.
The article says that in COM code should not delete the object, but call obj->destroy() instead. So to be "helpful" the author makes operator delete do the destroy call. Nasty!
Much better would have been to just declare a private operator delete, so the user cannot delete objects and must instead figure out the correct way.