Delete Calling Destructor But Not Deleting Object

Delete calling destructor but not deleting object?

You're misunderstanding what delete does. All delete does is call the destructor, and tell the allocator that that memory is free. It doesn't change the actual pointer. Anything beyond that is undefined.

In this case, it does nothing to the actual data pointed to. That pointer points to the same data it pointed to before, and calling methods on it works just fine. However, this behavior is not guaranteed; in fact, it's explicitly unspecified. delete could zero out the data; or the allocator could allocate that same memory for something else, or the compiler could just refuse to compile this.

C++ allows you to do many unsafe things, in the interest of performance. This is one of them. If you want to avoid this kind of mistake, it's a good idea to do:

delete ptr;
ptr = NULL;

to ensure that you don't try to reuse the pointer, and will crash immediately if you do rather than having undefined behavior.

Does delete[] call destructors?

If T has a destructor then it will be invoked by delete[]. From section 5.3.5 Delete of the c++11 standard (draft n3337), clause 6:

If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will
invoke the destructor (if any) for the object or the elements of the array being deleted
. In the case of an
array, the elements will be destroyed in order of decreasing address (that is, in reverse order of the completion
of their constructor; see 12.6.2).

The destructor for a type T will also be invoked for each element in an array of T[] when the array is not dynamically allocated and array goes out of scope (lifetime ends).


I need to know this, because the objects in my class do not contain sensible values all the time, so the destructors should not be called when they don't.

But, there seems to be a very significant problem with an object that can acquire a state where it cannot be destructed.

Why is the destructor not called in operator delete?

You are misusing operator new and operator delete. These operators are allocation and deallocation functions. They are not responsible for constructing or destructing objects. They are responsible only for providing the memory in which the object will be placed.

The global versions of these functions are ::operator new and ::operator delete.
::new and ::delete are new/delete-expressions, as are new/delete, differing from those, in that ::new and ::delete will bypass class-specific operator new/operator delete overloads.

The new/delete-expressions construct/destruct and allocate/deallocate (by calling the appropriate operator new or operator delete before construction or after destruction).

Since your overload is only responsible for the allocation/deallocation part, it should call ::operator new and ::operator delete instead of ::new and ::delete.

The delete in delete myClass; is responsible for calling the destructor.

::delete p; does not call the destructor because p has type void* and therefore the expression cannot know what destructor to call. It will probably call your replaced ::operator delete to deallocate the memory, although using a void* as operand to a delete-expression is ill-formed (see edit below).

::new MyClass(); calls your replaced ::operator new to allocate memory and constructs an object in it. The pointer to this object is returned as void* to the new-expression in MyClass* myClass = new MyClass();, which will then construct another object in this memory, ending the lifetime of the previous object without calling its destructor.


Edit:

Thanks to @M.M's comment on the question, I realized that a void* as operand to ::delete is actually ill-formed. ([expr.delete]/1) However, the major compilers seem to have decided to only warn about this, not error. Before it was made ill-formed, using ::delete on a void* had already undefined behavior, see this question.

Therefore, your program is ill-formed and you don't have any guarantee that the code actually does what I described above if it still managed to compile.


As pointed out by @SanderDeDycker below his answer, you also have undefined behavior because by constructing another object in the memory that already contains a MyClass object without calling that object's destructor first you are violating [basic.life]/5 which forbids doing so if the program depends on the destructor's side effects. In this case the printf statement in the destructor has such a side effect.

Why We Say Destructor Call When Object Goes out of Scope?

An object which goes out of scope has its destructor called. That is an unchangeable guarantee which is mandated by the C++ language standard. It doesn't matter if you've manually called the destructor beforehand; when it goes out of scope, the destructor will be called. If you've written your destructor such that bad things happen if it's called twice, or if the extra behavior which the compiler inserts into the destructor code doesn't want to be called twice, bad things will happen.

This is one of many reasons why you should never manually call a destructor.

how destructor is functioning when deleting a object of one class in other class

The problem is that destruct::destructObj needs to see the definition of Base to know that there is a destructor to call, but all it has is a forward declaration.

Change your code to this and it works.

#include <iostream>
using namespace std;
class base;

class destruct{
public :
destruct() {
cout<<"Destruct Constructor called"<<endl;
}

void destructObj(base* obj);

~destruct() {
cout<<"Destruct Destructor called"<<endl;
}
};

class base {
int runs;
public:

base(){

cout<<"Constructor called"<<endl;
}

~base(){
cout<<"destructor called"<<endl;
}
};

// *** this function after base has been defined ***
inline void destruct::destructObj(base* obj) {
delete obj;
}

int main() {
base *obj = new base();
destruct *desObj = new destruct();
desObj->destructObj(obj);
return 0;
}

Now this surprises me and I'm wondering if it's a g++ extension. I would have expected a compiler error when you tried to delete a pointer to a class where there is only a forward declaration. But I might be wrong.

UPDATE: apparently this (deleting a pointer to an incomplete class) is undefined behaviour, which I guess implies that it should compile. However your compiler really should be giving you a warning to tell you that there's a problem. Always pay attention to compiler warnings, and always compile with the maximum possible number of warnings enabled.

Will destructor delete built-in types and pointer objects?

What the spec means is that no code is run to clean up int i. It simply ceases to exist. Its memory is part of Foo and whenever a Foo instance is released, then i goes with it.

For pointers the same is true, the pointer itself will simply disappear (it's really just another number), but the pointer might point at something that needs to also be released. The compiler doesn't know if that is the case, so you have to write a destructor.

This is why things like std::shared_ptr exist; they are clever pointers (aka 'smart') and the compiler does know if it points at something that needs to be released and will generate the correct code to do so. This is why you should always use smart pointers instead of 'naked' ones (like int *p).

Is it possible to delete an object in c++ without calling the destructor?

You can set the pointers to NULL, then the destructor will not delete them.

struct WithPointers
{
int* ptr1;
int* ptr2;

WithPointers(): ptr1(NULL), ptr2(NULL) {}

~WithPointers()
{
delete ptr1;
delete ptr2;
}
}

...
WithPointers* object1 = new WithPointers;
WithPointers* object2 = new WithPointers;
object1->ptr1 = new int(11);
object1->ptr2 = new int(12);
object2->ptr1 = new int(999);
object2->ptr2 = new int(22);
...
int* pointer_to_999 = object2->ptr1;
object2->ptr1 = NULL;
delete object1;
delete object2; // the number 999 is not deleted now!
// Work with the number 999
delete pointer_to_999; // please remember to delete it at the end!


Related Topics



Leave a reply



Submit