Delete on already deleted object : behavior? - c++

I am wondering what will hapen if I try to do a delete on a pointer that is already deleted, or may have not been allocated ? I've read two things : first, that delete operator will do some checkings and we do not need to check if the pointer is null ; and then, I read that it can lead to unknown behaviors..
I'm asking it, because I use some personal objects that contains Qt objects attributes ; I think that Qt delete all widgets associated when we close the window, but I'm not pretty sure and still : if the soft crash before the window's close, we have to delete all objects manually.
So, what would be the best solution ? Something like that ?
if( my_object )
delete my_object;
Can it avoid dangerous behaviours ?

delete on an already deleted non-null pointer is undefined behavior - your program will likely crash. You can safely use delete on a null pointer - it will yield a no-op.
So the real problem is not delete on a null pointer. The real problem is here:
ptr = new Something();
otherPtr = ptr;
delete ptr;
delete otherPtr;
This can happen if you have several pointers to the same object and it is quite dangerous. The possible solutions are:
use smart pointers (no delete in your code) or
only have one designated pointer for controlling each object lifetime and delete at exactly the right time.

if( my_object )
delete my_object;
is redundant. delete on a NULL pointer does nothing. This is guaranteed by the standard.
delete on a pointer that was already deleted causes undefined behavior. That's why you should always remember to assign your pointers to NULL after you delete them:
delete p;
p = NULL;
EDIT: As per the comments, I feel I should specify this. If you have multiple pointers to the same object, the assignment to NULL won't make the delete safe. Regardless, it's better to use smart pointers.

Please note that deleting a pointer does not set it to NULL.
int* i = new int;
*i = 42;
delete i;
delete i; // oops! i is still pointing to the same memory, but it has been deleted already
Deleting a null pointer doesn't do anything, deleting an already deleted object will result in undefined behaviour.

the right way is:
if( my_object )
{
delete my_object;
my_object = NULL;
}
because, calling twice the way it was before will call delete on a deleted pointer.

It results in Undefined Behavior if you call delete on already deleted pointer.
Calling delete on a NULL pointer has no-effect though.
Standard c++03 § 3.7.4.2-3
If a deallocation function terminates by throwing an exception, the behavior is undefined. The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect. Otherwise, the value supplied
to operator delete(void*) in the standard library shall be one of the values returned by a previous invocation of either operator new(std::size_t) or operator new(std::size_t, const std::nothrow_-t&) in the standard library, and the value supplied to operator delete[](void*) in the standard library shall be one of the values returned by a previous invocation of either operator new[](std::size_t) or
operator new[](std::size_t, const std::nothrow_t&) in the standard library.
Using RAII & Smart Pointers are your best weapons to avoid such problems.

Just to combine the answers above:
if (my_object) checks the value of the pointer, not the existence of the object. If it is already deleted, the pointer may still point to that location.
deleting an already deleted object is undefined behavior and will probably crash your program.
deleting NULL is defined and does nothing. Together with point 1 this explains the answer of Luchian.
To sum it up: You have to be clear on who owns the object and where the different pointer to the object are. When you delete an object, make sure to set all pointer pointing to that location to 0/NULL. Use managing objects like boost::shared_pointer or QPointer to help you in this task.

Related

c++ do I need to manually delete a void* pointer which is then pointing to another concrete type?

Assume I have a pointer void* p, then after some passing in and out of functions, let's say p is now pointing to int. Then do I need to manually delete as delete static_cast<int*>(p)?
In most places people say delete only happen when there is new. But in this case, it's not but does C++ itself remember to release that memory?
That all depends on how the int you're pointing to was allocated, you only delete what you new.
Correct (the int is new'd):
int* a = new int;
void* p = a;
//somewhere later...
delete static_cast<int*>(p);
Bad (the int is automatically managed):
int a = 0;
void* p = &a;
//somewhere later...
delete static_cast<int*>(p);
Answering the comment code, doing:
int* a = new int;
void* p = a;
delete p;
Is never okay. You should never delete through a void*, it's undefined behavior.
side note : in modern C++ you really shouldn't be using new or delete, stick with smart pointers or standard containers.
The short answer is: "It depends".
In most places people say delete only happen when there is new.
That's true so far as it goes. To avoid wasting resources and to ensure all destructors are called correctly every new has to be balanced by a delete somewhere. If your code can follow several paths you have to make sure that every path calls delete (if calling delete is appropriate).
The can get tricky when exceptions are thrown which is one reason why Modern C++ programmers generally avoid using new and delete. Instead they use the smart pointers std::unique_ptr and std::shared_ptr along with the helper template functions std::make_unique<T> and std::make_shared<T> (see the SO question: What is a smart pointer and when should I use one?) to implement a technique known as RAII (Resource Acquisition Is Instantiation).
But in this case, it's not …
Remember that the phrase ... when there is a new refers to the object the pointer points to not the pointer itself. Consider the following code...
int *a = new int();
void *p = a;
if (SomeTest())
{
delete a;
}
else
{
a = nullptr;
}
// This line is needed if SomeTest() returned false
// and undefined (dangerous) if SomeTest() returned true
delete static_cast<int *> (p);
Is that last line of code needed?
The object that a and p both point to was created by calling new so delete has to be called on something. If the function SomeTest() returned false then a has been set to nullptr so calling delete on it won't affect the object we created. Which means we do need that last line of code to properly delete the object that was newed up in the first line of code.
On the other hand, if the function SomeTest() returned true then we've already called delete for the object via the pointer a. In that case the last line of code is not needed and in fact may be dangerous.
The C++ standard says that calling delete on an object that has already been deleted results in "undefined behaviour" which means anything could happen. See the SO question: What happens in a double delete?
does C++ itself remember to release that memory?
Not for anything created by calling new. When you call new you are telling the compiler "I've got this, I will release that memory (by calling delete) when appropriate".
do I need to manually delete
Yes: if the object pointed to needs to be deleted here and the void * pointer is the only pointer you can use to delete the object.

Why need to set rvalue reference to null in move constructor?

I've read the post: Why do we need to set rvalue reference to null in move constructor?
It said that during a move, you just copied the pointer from one object to another, so two pointers points to the temporary object. And when the temporary object goes out of scope, its destructor will run. And then the object pointed by 2 pointers would be deallocates. So the pointer field of object constructed by move constructor would point to unavailable place.
However, look at following code:
int *p = new int(3);
int *q = p;
delete p;
std::cout << *q << std::endl;
after delete the pointer p, pointer q could still access the int object.
So, is that just because when the object is accessed by rvalue reference causes the difference?
No you can't. It appears to work, but it's entirely undefined behavior. The memory is released to the runtime.
When you move something, you're effectively saying the original object is no longer valid - you only access its original contents from the moved-to object. Furthermore, the set to NULL after a move prevents a double-delete - when the original objects goes out of scope and attempts to free that memory, it will either fail straight away (if the new object already free'd it) or the new object will fail when it itself attempts to release that memory.
Accessing deleted memory of the free store is undefined behavior.
On move construction, the pointer of the object constructed is set to the pointer of the rvalue, which in turn is set to nullptr afterwards.
The object referenced by the rvalue ends its lifetime thereafter, after all it is a temporary. Therefore, the pointer set to nullptr is not expected to be used anymore. When it is destructed, delete nullptr; is executed, i.e., a no-op.
OTOH, when the lifetime of the constructed object ends, the actual resource is deleted - the pointer to it was assigned in the move constructor.
No, after delete the pointer p, pointer q cannot still access the int object. If you think otherwise because you ran it and got 3 in the output--that's because you caused undefined behavior and UB can "work" as one of its many, many options.
In general what happens is that the memory address hasn't been reused yet, still belongs to the program (so it has permission to access and the value has not been erased), so you'll see whatever value was deleted in that memory. All this means that it will appear as if the code is perfectly OK when it's not. You could also print using *p in this case and it would be no different. The p and q variables both contain the same address...which was freed by a delete.
One interesting aspect of this is that high security applications, or encryption applications like GPG, manually fill deleted memory with garbage so that it can't just be sniffed out--giving access to private keys out to the world. Otherwise the key would still just be written in RAM until someone writes something else there!
This is the problem with pointers. They do not convey ownership semantics.
You should be using something like std::unique_ptr. When you move the pointer from one object to another the old object recognizes it no longer owns the object and thus you can;t access the data.
Simple solution. Like the rest of the C++ community stop using pointers like this.
std::unqieu_ptr<int> p(new int(3));
std::unique_ptr<int> q = p; // Fails to compile
std::unqieu_ptr<int> p(new int(3));
std::unique_ptr<int> q = std::move(p); // explicitly transfer ownership.
// delete p; // No longer need this as when the onbject goes out of scope
// it is deleted.
Both the question you linked and your question is trying to avoid undefined behavior upon dereferencing of q.
The thing is that, (in the linked question) you have to know that you can't dereference q anymore (you aren't managing it) by setting it to nullptr. But here, it's your business to not to dereference q after the delete. It's extremely predictable that q will be deleted before std::cout << *q << std::endl;. It's your fault that you're dereferencing it!
Nevertheless, setting q to nullptr helps with debugging, delete q is no longer UB, and nullptr signifies a pointer to non-existent object.

deallocation of same pointer twice not giving error if I make the pointer NULL

I tried to deallocate same pointer twice and it failed, but if I follow the same steps with not making it NULL the code runs fine.
#include <iostream>
struct MyClass {
MyClass() {std::cout << "Allocated and Constructed" << std::endl ;}
};
int main () {
// allocates and constructs five objects:
MyClass * p1 = new MyClass[5];
delete[] p1;
delete[] p1; // The code will succeed if I comment this line of code
p1=NULL;
delete[] p1;
delete[] p1;
return 0;
}
I see a good answer to the question What happens when you deallocate a pointer twice or more in C++? but what makes it run if I make it NULL, shouldn't be the same behaviour to follow for both the cases?
You need to deallocate only what you allocate. You allocate five instances of MyClass with new[]. So that's what you need to deallocate.
You're not deallocating any pointers. Pointers don't need to be deallocated unless you dynamically allocated them, and your code doesn't dynamically allocate any pointers.
When you make the pointer nullptr (or NULL), it doesn't point to anything. So calling delete on it has no effect. The C++ standard chose to make calling delete (or delete[]) on a null pointer do nothing.
delete[] p1; doesn't ususally change the actual value of p1. (Although the C++ standard states that it can set p1 to nullptr on doing this, no compiler I've worked with actually does this).
So the behaviour on a second call to delete[] p1; is undefined since your program no longer owns that memory.
Some programmers consider it good practice to set p1 = nullptr explicitly after a delete[] since then a subsequent delete is benign. But doing that can hide other memory management issues your program has (why would your program attempt to delete the same block of memory more than once?), so I'd advise against it.
From the standard, 5.3.5$2 Delete [expr.delete] (bold by me)
In the first alternative (delete object), the value of the operand of
delete may be a null pointer value, a pointer to a non-array object
created by a previous new-expression, or a pointer to a subobject
(1.8) representing a base class of such an object (Clause 10). If not,
the behavior is undefined. In the second alternative (delete array),
the value of the operand of delete may be a null pointer value or a
pointer value that resulted from a previous array
new-expression.81 If not, the behavior is undefined.
It explains why delete a pointer twice is UB, and delete a null pointer is well defined.

C++ trouble with pointers to objects

I have a class with a vector of pointers to objects. I've introduced some elements on this vector, and on my main file I've managed to print them and add others with no problems. Now I'm trying to remove an element from that vector and check to see if it's not NULL but it is not working.
I'm filling it with on class Test:
Other *a = new Other(1,1);
Other *b = new Other(2,2);
Other *c = new Other(3,3);
v->push_back(a);
v->push_back(b);
v->push_back(c);
And on my main file I have:
Test t;
(...)
Other *pointer = t.vect->at(0);
delete t.vect->at(0);
t.vect->erase(t.vect->begin());
if (pointer == NULL) { cout << "Nothing here.."; } // Never enters here..
Deleting a pointer doesn't have to zero it, it just frees the memory assigned there. Using pointer is undefined after the delete though, as the memory is free to be used for other things. Technically the C++ spec intentionally leaves it up to implementations whether they want to zero a deleted pointer or not, but practically none that I know of do so
The deletion of memory pointed by a pointer, doesn't set the pointer to NULL.
You set pointer equal to the address of something, and never touched it again, so of course it won't be null. The fact that you then did something to the object is irrelevant.
Using simple pointers, there is no safe way for pointer to determine whether the object it once pointed to has been deleted. The simplest way to do what you seem to want to do is by leaving it to the containers: if you're interested in that object, search for pointer in the vector to see whether it's still there (and don't delete the object without erasing the corresponding element from the vector, or you'll have the same problem all over again).
To overcome the checking a deleted ptr problem you could use boost::shared_ptr.
Instead of delete use .reset() and to check if the ptr is still valid use .get()
(Actually you can just use if(p) where p is the shared_ptr because it has a conversion to bool)

Is there any reason to check for a NULL pointer before deleting?

I often see legacy code checking for NULL before deleting a pointer, similar to,
if (NULL != pSomeObject)
{
delete pSomeObject;
pSomeObject = NULL;
}
Is there any reason to checking for a NULL pointer before deleting it? What is the reason for setting the pointer to NULL afterwards?
It's perfectly "safe" to delete a null pointer; it effectively amounts to a no-op.
The reason you might want to check for null before you delete is that trying to delete a null pointer could indicate a bug in your program.
Edit
NOTE: if you overload the delete operator, it may no longer be "safe" to delete NULL
The C++ standard guarantees that it is legal to use a null pointer in a delete-expression (§8.5.2.5/2). However, it is unspecified whether this will call a deallocation function (operator delete or operator delete[]; §8.5.2.5/7, note).
If a default deallocation function (i.e. provided by the standard library) is called with a null pointer, then the call has no effect (§6.6.4.4.2/3).
But it is unspecified what happens if the deallocation function is not provided by the standard library — i.e. what happens when we overload operator delete (or operator delete[]).
A competent programmer would handle null pointers accordingly inside the deallocation function, rather than before the call, as shown in OP’s code.Likewise, setting the pointer to nullptr/NULL after the deletion only serves very limited purpose. Some people like to do this in the spirit of defensive programming: it will make program behaviour slightly more predictable in the case of a bug: accessing the pointer after deletion will result in a null pointer access rather than a access to a random memory location. Although both operations are undefined behaviour, the behaviour of a null pointer access is a lot more predictable in practice (it most often results in a direct crash rather than memory corruption). Since memory corruptions are especially hard to debug, resetting deleted pointers aids debugging.
— Of course this is treating the symptom rather than the cause (i.e. the bug). You should treat resetting pointers as code smell. Clean, modern C++ code will make memory ownership clear and statically checked (by using smart pointers or equivalent mechanisms), and thus provably avoid this situation.
Bonus: An explanation of overloaded operator delete:
operator delete is (despite its name) a function that may be overloaded like any other function. This function gets called internally for every call of operator delete with matching arguments. The same is true for operator new.
Overloading operator new (and then also operator delete) makes sense in some situations when you want to control precisely how memory is allocated. Doing this isn't even very hard, but a few precautions must be made to ensure correct behaviour. Scott Meyers describes this in great detail Effective C++.
For now, let's just say that we want to overload the global version of operator new for debugging. Before we do this, one short notice about what happens in the following code:
klass* pobj = new klass;
// … use pobj.
delete pobj;
What actually happens here? Well the above can be roughly translated to the following code:
// 1st step: allocate memory
klass* pobj = static_cast<klass*>(operator new(sizeof(klass)));
// 2nd step: construct object in that memory, using placement new:
new (pobj) klass();
// … use pobj.
// 3rd step: call destructor on pobj:
pobj->~klass();
// 4th step: free memory
operator delete(pobj);
Notice step 2 where we call new with a slightly odd syntax. This is a call to so-called placement new which takes an address and constructs an object at that address. This operator can be overloaded as well. In this case, it just serves to call the constructor of the class klass.
Now, without further ado here's the code for an overloaded version of the operators:
void* operator new(size_t size) {
// See Effective C++, Item 8 for an explanation.
if (size == 0)
size = 1;
cerr << "Allocating " << size << " bytes of memory:";
while (true) {
void* ret = custom_malloc(size);
if (ret != 0) {
cerr << " # " << ret << endl;
return ret;
}
// Retrieve and call new handler, if available.
new_handler handler = set_new_handler(0);
set_new_handler(handler);
if (handler == 0)
throw bad_alloc();
else
(*handler)();
}
}
void operator delete(void* p) {
cerr << "Freeing pointer # " << p << "." << endl;
custom_free(p);
}
This code just uses a custom implementation of malloc/free internally, as do most implementations. It also creates a debugging output. Consider the following code:
int main() {
int* pi = new int(42);
cout << *pi << endl;
delete pi;
}
It yielded the following output:
Allocating 4 bytes of memory: # 0x100160
42
Freeing pointer # 0x100160.
Now, this code does something fundamentally different than the standard implementation of operator delete: It didn't test for null pointers! The compiler doesn't check this so the above code compiles but it may give nasty errors at run-time when you try to delete null pointers.
However, as I said before, this behaviour is actually unexpected and a library writer should take care to check for null pointers in the operator delete. This version is much improved:
void operator delete(void* p) {
if (p == 0) return;
cerr << "Freeing pointer # " << p << "." << endl;
free(p);
}
In conclusion, although a sloppy implementation of operator delete may require explicit null checks in the client code, this is non-standard behaviour and should only be tolerated in legacy support (if at all).
Deleting null is a no-op. There's no reason to check for null before calling delete.
You might want to check for null for other reasons if the pointer being null carries some additional information you care about.
Delete checks for NULL internally. Your test is redundent
According to C++03 5.3.5/2, it's safe to delete a null pointer.
This following is quoted from the standard:
In either alternative, if the value of the operand of delete is the
null pointer the operation has no effect.
If pSomeObject is NULL, delete won't do anything. So no, you don't have to check for NULL.
We consider it good practice to assign NULL to the pointer after deleting it if it's at all possible that some knucklehead can attempt to use the pointer. Using a NULL pointer is slightly better than using a pointer to who knows what (the NULL pointer will cause a crash, the pointer to deleted memory may not)
There is no reason to check for NULL prior to delete.
Assigning NULL after delete might be necessary if somewhere in the code checks are made whether some object is already allocated by performing a NULL check. An example would be some sort of cached data that is allocated on demand. Whenever you clear out the cache-object you assign NULL to the pointer so the code that allocates the object knows that it needs to perform an allocation.
I believe the previous developer coded it "redundantly" to save some milliseconds:
It's a good thing to have the pointer be set to NULL upon being deleted, so you could use a line like the following right after deleting the object:
if(pSomeObject1!=NULL) pSomeObject1=NULL;
But then delete is doing that exact comparison anyway (doing nothing if it's NULL). Why do this twice? You can always assign pSomeObject to NULL after calling delete, regardless of its current value - but this would be slightly redundant if it had that value already.
So my bet is the author of those lines tried to ensure pSomeObject1 would always be NULL after being deleted, without incurring the cost of a potentially unnecessary test and assignation.
It depends on what you are doing. Some older implementations of free, for example, will not be happy if they are passed a NULL pointer. Some libraries still have this problem. For example, XFree in the Xlib library says:
DESCRIPTION
The XFree function is a
general-purpose Xlib routine that
frees the specified data. You must
use it to free any objects that were
allocated by Xlib, unless an alternate
function is explicitly specified for
the object. A NULL pointer cannot be
passed to this function.
So consider freeing NULL pointers as a bug and you'll be safe.
As for my observations, deleting a null pointer using delete is safe in unix based machines ike PARISC and itanium. But is quite unsafe for Linux systems as the process would crash then.