I wrote this to analyse the behavior of the destructor function of a class and its effect on memory deallocation, but the result seems to be a bit surprising to me:
class test {
public:
test() {}
~test() {} //<-----Run the program once with and once without this line.
};
int main()
{
test x;
test *a(&x);
cout << "a before memory allocation: " << a << endl;
a = new test;
cout << "a after memory allocation and before delete: " << a << endl;
delete a;
cout << "a after delete: " << a << endl;
return 0;
}
With default destructor the result is:
But with my own destructor it's:
Isn't the second result erroneous? Because somewhere I read that:
the deallocation function shall deallocate the storage referenced by the pointer, rendering invalid all pointers referring to any part of the deallocated storage.
Maybe I'm not following it correctly(especially due to the difficult English words used!). Would you please explain to me why is this happening?
What's exactly the difference between my simply defined destructor and the C++ default destructor?
Thanks for your help in advance.
If a is a (non-null) pointer to an object, then operation delete a triggers the destructor of the object to which a is pointing to (the default destructor or a specific one) and finally frees the memory that had been allocated for this object. The memory to which a has pointed is not a valid object any more, and a must not be dereferenced any more. However, delete a does not set the value of pointer a back to a specific value. Actually I'm surprised that delete a in your case changed the value of a; I cannot reproduce this behaviour.
Related
This question already has answers here:
explicit call to destructor is not destroying my object why?
(7 answers)
Closed 4 years ago.
I want to explicitly call the destructor of an object in C++ to destroy that object.
This is just a simple program to experiment with the features of the programming languages. I have a default constructor which sets the internal data member to 1, and overloaded constructor which sets the internal data member to the parameter, and a destructor which displays the internal data member of the just destroyed object. There is also a function which prints the internal data member.
#include <iostream>
using std::cout;
using std::endl;
class myClass {
public:
myClass()
{
i = 1;
cout << "default ";
cout << "constructor called with " << this->i << endl;
}
myClass(int i)
{
this->i = i;
cout << "constructor called with " << this->i << endl;
}
~myClass()
{
cout << "object " << i << " destroyed!" << endl;
}
void printData()
{
cout << "object's data is " << i << endl;
}
private:
int i; // private data member
};
int main() {
myClass a;
myClass b;
myClass c(8);
a.printData();
b.printData();
c.printData();
/* I want to explicitly destroy object b. */
b.~myClass();
b.printData();
/* all the destructors get called when the objects go out of scope */
return 0;
}
My reasoning is this: I think that the destructor causes the object to be destroyed, so it no longer exists in the memory. After I explicitly call the destructor, I should be no longer able to use that object again, since it is destroyed. However, I am able to call a function of the object and print the value of the internal data member. Did manually calling the destructor fail to destroy the object? What's going on here?
Output:
default constructor called with 1
default constructor called with 1
constructor called with 8
object's data is 1
object's data is 1
object's data is 8
object 1 destroyed!
object's data is 1
object 8 destroyed!
object 1 destroyed!
object 1 destroyed!
Does calling the destructor destroy the object, or is calling the destructor a RESULT OF destroying the object?
After I explicitly call the destructor, I should be no longer able to use that object again, since it is destroyed
That's right. Only that it's C++ and instead of "you are no longer able" as in "you'll be warned when you do bad things", it's more like "you may be shot in the foot at any random point in the future without warning if you do bad things" (aka "undefined behavior").
In your particular example, you destroy the object, and it ceases to logically exist. The memory may still be allocated or even contain some old data. However, trying to access it is undefined behavior. It may "kind of work" on your specific combination of compiler, compiler flags, source code, OS and moon phase, it may work differently later, it technically may even wipe your hard drive.
Also, as you've declared the object in a local variable, it gets automatically destroyed second time when it goes out of the scope. That's also undefined behavior, but it does not really matter is your program's behavior is already completely undefined.
You may try catching such things with dynamical analysis like Valgrind, AddressSanitizer or UndefinedBehaviorSanitizer, but they provide no guarantees.
My friend told me C++ allows us to call a member function even if the instance is destroyed from memory. So I write the code below to verify it, but why the value of a can be extracted even after the object was destroyed? I thought there would be a segment fault.
#include <iostream>
class Foo{
public:
Foo(int a = 0){
std::cout << "created" << std::endl;
this->a = a;
}
~Foo(){
std::cout << "destroyed" << std::endl;
}
Foo *f(){
std::cout << "a=" << a << std::endl;
return this;
}
private:
int a;
};
Foo *iwanttocallf(int i){
return ((Foo)i).f();
}
int main(){
for(int i = 0; i < 3; i++)
iwanttocallf(i)->f();
}
Output from my Macbook Air:
created
a=0
destroyed
a=0
created
a=1
destroyed
a=1
created
a=2
destroyed
a=2
Usually compilers are implementing the member function call as a call to a regular c function with the first argument a pointer to the object (gcc does it like that as far as I know). Now if your pointer is pointing to one destroyed object it doesn't mean that the memory where the a has been stored will be changed, it might be changed. So it is undefined behavior in general. In your case you got a value of a but maybe next time with a different compiler or different code you will crash. Try to use placement new operator then set a value of 'a' = 0 in destructor... and follow the memory where the object is stored.
"My friend told me C++ allows us to call a member function even if the member is destroyed from memory"?
I don't know what your friend is trying to say. But you call member function on some object of a class
unless it's a static member. So, if you delete that object from memory, how could you call any function of that class on that object. It's an undefined behavior.
This is covered in ยง12.7 [class.cdtor]:
[..] For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor
finishes execution results in undefined behavior.
As other people have told, this involves undefined behavior, and any result is possible. I'll try to explain why you encountered this particular result (stuff working normally).
Objects in C++ are represented by contents of memory. When an object is destroyed, its
destructor is executed, but the memory still contains the previous value. The output operation outputs the value taken from memory (which is now "free" - doesn't belong to any object) - if there is not much stuff going on between the destructor call and the output, the old value will remain.
However, if you change your code to add some calculations, the bug will be evident. For example, I added the following function that simulates some calculations:
int do_stuff()
{
int result = 0;
int x[3] = {0};
for (auto& n: x)
{
n = rand();
result ^= n;
}
return result;
}
I also added a call to this function:
Foo *f(){
std::cout << "foo1: a=" << a << std::endl;
do_stuff();
std::cout << "foo2: a=" << a << std::endl;
return this;
}
I got the output:
foo1: a=0
foo2: a=424238335
This clearly shows that it's not safe to expect anything consistent when dealing with deleted objects.
By the way, some debuggers overwrite the memory that deleted objects occupied with a special value like 0xcdcdcdcd - to make some sense out of this kind of unpredictable behavior. If you execute your code under such a debugger, you will see garbage printed, and will immediately know that your code is buggy.
As shown here, one can use dynamic_cast to detect a deleted pointer:
#include <iostream>
using namespace std;
class A
{
public:
A() {}
virtual ~A() {}
};
class B : public A
{
public:
B() {}
};
int main()
{
B* pB = new B;
cout << "dynamic_cast<B*>( pB) ";
cout << ( dynamic_cast<B*>(pB) ? "worked" : "failed") << endl;
cout << "dynamic_cast<B*>( (A*)pB) ";
cout << ( dynamic_cast<B*>( (A*)pB) ? "worked" : "failed") << endl;
delete pB;
cout << "dynamic_cast<B*>( pB) ";
cout << ( dynamic_cast<B*>(pB) ? "worked" : "failed") << endl;
cout << "dynamic_cast<B*>( (A*)pB) ";
cout << ( dynamic_cast<B*>( (A*)pB) ? "worked" : "failed") << endl;
}
the output:
dynamic_cast<B*>( pB) worked
dynamic_cast<B*>( (A*)pB) worked
dynamic_cast<B*>( pB) worked
dynamic_cast<B*>( (A*)pB) failed
It explains that the deletion of the vtable is detected.
But I am wondering how is that possible since we do not overwrite the freed memory?
And is that solution fully portable ?
Thanks
First off, trying to use a deleted object in any form results in undefined behavior: whatever result you see could happen!
The reason of the observed behavior is simply that an object changes type during destruction: from being an object of the concrete type it change through all of the types in the hierarchy. At each point the virtual functions change and the vtable (or similar) gets replaced. The dynamic_cast<...>() simply detects this change in the bytes strored at the location of the object.
In case you feel like wanting to show that this technique doesn't reliably work you can just set the content of deleted memory to a random bit pattern or the bit pattern of an object of the most derived type: a random bit pattern probably yields a crash and memcpy() probably claims that the object is still life. Of course, since it is undefined behavior anything can happen.
One relevant section on this 3.8 [basic.life] paragraph 5:
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, 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 will be or was located may be used but only in limited ways. For an object under construction or destruction, see 12.7. Otherwise, such a pointer refers to allocated storage (3.7.4.2), and using the pointer as if the pointer were of type void*,
is well-defined. Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below. The program has undefined behavior if:
...
the pointer is used as the operand of a dynamic_cast (5.2.7). ...
Oddly, the example on the last bullet on dynamic_cast doesn't use dynamic_cast.
Of course, the object is also probably released in which case the above guarantees don't even apply.
I try to understand what happen when an object destroy on stack.
here is my sample code:
#include <stdio.h>
struct B {
~B() {puts("BBBB");}
};
int main()
{
B b;
b.~B();
}
output is
BBBB
BBBB
based on the output, I can tell the object is destroy twice.one is ~B(), another one is after "}". how and why can a object get destroy twice?
update:
after i review replies, I think the destructor doesnt destroy this object. it there a way to destroy an object before it reach out of scope "}".
Thanks
You are not supposed to invoke the destructor by hand. What's happening is you are invoking the destructor and then when the object gets popped off the stack the destructor is called again automatically by the compiler.
~B() is called before the destruction
Destructors are usually used to deallocate memory and do other cleanup
for a class object and its class members when the object is destroyed.
A destructor is called for a class object when that object passes out
of scope or is explicitly deleted.
Source
So you are just calling a function twice.
There's minimal-to-no garbage collection in C++, objects are simply destroyed when they go out of scope. So you could replace your test to this:
#include <iostream>
struct B {
B() { std::cout << "B()" << std::endl; }
~B() { std::cout << "~B()" << std::endl; }
};
int main()
{
std::cout << "start main" << std::endl;
{ // scope
std::cout << "start scope" << std::endl;
B b;
std::cout << "end scope" << std::endl;
} // <-- b gets destroyed here.
std::cout << "end main" << std::endl;
}
If you want an object on the stack over which you have control over the lifetime of, you can do something like this:
#include <iostream>
#include <memory.h>
struct B {
B() { std::cout << "B()" << std::endl; }
~B() { std::cout << "~B()" << std::endl; }
};
int main()
{
std::cout << "start main" << std::endl;
{ // scope
std::cout << "start scope" << std::endl;
void* stackStorage = alloca(sizeof(B));
std::cout << "alloca'd" << std::endl;
// use "in-place new" to construct an instance of B
// at the address pointed to by stackStorage.
B* b = new (stackStorage) B();
std::cout << "ctord" << std::endl;
b->~B(); // <-- we're responsible for dtoring this object.
std::cout << "end scope" << std::endl;
} // <-- b gets destroyed here, but it's just a pointer.
std::cout << "end main" << std::endl;
}
Live demo: http://ideone.com/ziNjkd
Remember, though, it's the stack. When it goes out of scope, it goes away - if you don't destroy it, it just dissapears.
{
void* stackStorage = alloca(sizeof(B));
B* b = new (stackStorage) B(); // "in-place new"
} // (*b)s memory is released but (*b) was not dtord.
The only time you would manually call a destructor is when you've got grounds to use placement new
Keep in mind that the destructor is like any other function. The only difference with other function is that it is automatically called when the object is deallocated. You cann see this like an event. You get a chance to clean everything before the object get annihilated. Calling the destructor by hand does not deallocate the object.
Object construction/destruction in C++ follows this simple rule:
Anything automatically allocated (and constructed) is automatically destructed.
Anything explicitely allocated with new is explicitely destructed via delete.
Anything explicitely constructed with new() must be explicitely destructed by calling the destructor.
The destructor has to be called in all three cases, the difference is in how the memory for the object is allocated:
The object is on the stack, its allocation is managed by the compiler.
The object is on the heap, its allocation is managed by the programmer.
The object is anywhere, construction and destruction is independent of allocation.
In the first two cases, we have a combination of allocation and construction, and consequently a combination of destruction and deallocation. The third case is entirely different, but fully supported by the language, and the reason that you are allowed to explicitely call a destructor; because in this case an object is constructed without allocating memory for it. Consequently, it must be destructible without deallocating memory as well. This case can be used like this:
void* buffer = (void*)new char[sizeof(Foo)]; //allocation
Foo* myFoo = new(buffer) Foo(); //construction
myFoo->~Foo(); //destruction
Foo* anotherFoo = new(buffer) Foo(); //reuse the buffer to construct another object in it
anotherFoo->~Foo(); //destruction of the second object
delete buffer; //deallocation
Note, that this actually constructs two objects, one after the other in the same place, destructing them explicitely before the memory is reused. The buffer could also be a large slap of memory to store many objects, std::vector<> works like this.
So, yes, destruction does destroy your object, you must not use it after destruction. But since you used an automatically allocated and constructed object in your question, the compiler also took care of destructing it, leading to the double destruction. This is always a bug, objects must never be destructed twice, but the language allows you to do it anyway.
What you are doing is a pretty good example of a variable running out of scope.
int main()
{
//Main is started
B b;
/* What happens is that `b` is constructed as a local
variable and put on the runtime stack.*/
b.~B();
/*You then invoke the destructor manually which is bad practice.
But it is possible and it will execute the code.
However, the state of the resulting instance is undefined.*/
}
/*Main ends and local variables defined in the
current scope get destroyed. Which also means that B's destructor
is called the second time */
FYI - the only time you are supposed to do manual destruction of an object is when it is put on the heap like this:
// create an instance of B on the heap
B* b = new B();
// remove instance and implicitly call b's destructor.
delete b;
i would like to answer my own question.
after a lot of reading, Here is my summary.
1. destructor doesnt destroy it's object. the object stays at stack
until out of scope.
2. nothing can destroy a stack object.
3. the destructor did destroy RESOURCE inside the object.
sample code:
struct B {
B() {happy="today is a good day"; hour = 7;}
~B() {puts("BBBB");}
std::string happy;
int hour;
};
int main()
{
B b;
std::cout << b.happy << b.hour <<std::endl;
b.~B();
std::cout << b.happy << b.hour <<std::endl;
}
output:
today is a good day7
BBBB
7
BBBB
we can see a resource b.happy is gone after b.~B() is called. this is a proof of my point 3.
you see the b.hour(int type is not a resource) is still here. this is a proof of my point 1.
I have a few doubts related to destructor.
class cls
{
char *ch;
public:
cls(const char* _ch)
{
cout<<"\nconstructor called";
ch = new char[strlen(_ch)];
strcpy(ch,_ch);
}
~cls()
{
//will this destructor automatically delete char array ch on heap?
//delete[] ch; including this is throwing heap corruption error
}
void operator delete(void* ptr)
{
cout<<"\noperator delete called";
free(ptr);
}
};
int main()
{
cls* cs = new cls("hello!");
delete(cs);
getchar();
}
Also, as a destructor is automatically called upon delete why do we need an explicit delete when all the logic can be written in destructor?
I am super confused regarding operator delete and destructor and couldn't make out their specific usage. An elaborate description would be very helpful.
EDIT:
My understanding based on the answers:
For this particular case, a default destructor will corrupt the char pointer so we need to explicitly delete the char array first other wise it will result in memory leak. Please correct me if I am wrong.
Well, a default destructor deallocates memory that is used by member variables (i.e. the member pointer ch itself ceases to exist), but it does not automatically deallocate any memory that is referenced by member pointers. So there is a memory leak in your example.
delete is not a function (though you can overload it); and yes, it is good practice that the logic for the deallocation be written in the destructor. But it is incorrect to assume that the deallocation will be automatically performed by the destructor. The thing is that the destructor will be called at the end of the object's lifetime, but what it does it dependent upon the code you write for it. That is, you should call delete[] on ch inside the destructor:
~cls()
{
delete[] ch;
ch = nullptr;
}
Moreover, I believe the heap corruption error is coming from that fact that you did not leave enough room in the initialization of ch for the null byte \0. You should also be using the the member-initializer list. Change your constructor to this:
cls(const char* _ch) : ch(new char[1+strlen(_ch)])
{
std::cout << "\nconstructor called";
std::strcpy(ch, _ch);
}
There are many improvements that can be made to your code. Namely, using std::string and following the Rule Of Three. Your code also doesn't need a operator delete() overload. cs should be stack allocated:
#include <iostream>
#include <string>
class cls
{
std::string ch;
public:
cls() { std::cout << "default constructor called\n"; }
cls(std::string _ch) : ch(_ch)
{
std::cout << "constructor called\n";
}
cls(cls const& other) : ch(other.ch)
{
std::cout << "copy-constructor called\n";
}
~cls() { std::cout << "destructor called\n"; }
};
int main()
{
cls cs("hello!");
std::cin.get();
} // <-- destructor gets called automatically for cs
No, the destructor won't magically delete the memory pointed to by ch for you. If you called new (you did in the constructor) then you must also call delete at some appropriate time.
A destructor executes when an object is being destroyed. This can be when an automatic object (that is something allocated on the stack) is about to go out of scope, or when you explicitly delete an object allocated with new.
Generally, think of new as a way of getting memory allocated, a constructor as a way of taking that memory and making it into an object, a destructor as taking an object and destroying it, leaving behind a chunk of memory and delete as taking that chunk of memory and deallocating it.
As a convenience for you, when you call new the compiler will call the constructor for you after it allocates the memory you requested and when you call delete the compiler will automatically invoke the destructor for you.
You are getting heap corruption errors because you have a buffer oveflow: you are not allocating space for the null terminating byte that strcpy appends.
Remember a C string is a sequence of bytes followed by a null byte. This means that a string of length 5 actually requires 6 bytes to store.
Also remember that you can and should use std::string instead of C style arrays to save yourself the trouble and avoid having to write error-prone code when there's a very robust and full-featured implementation already available for your use.
With the notable exception of homework/learning exercises, there is hardly a situation where you should implement C style strings directly instead of using std::string.
The same (albeit a little less strict) goes for dynamic arrays in general. Use std::vector instead.
There is no use in override the delete Operator for a specific class. That's what the global delete Operator is for.
What you should do is a delete[] on ch in the destructor. This has to be done explicitly, as the delete Operator only deallocates the memory directly allocated to store the class' instance. As you are allocating further Memory in the constructor you have to free it upon destruction.
As a rule of thumb you can assume that con- and destructor need to be coded symmetricly. For every new in the constructor, has to be a delete in de destructor.
Oh and by the way: You must not mix C++ allocators (new/delete) with C allocators (malloc/free). What you allocate in C++, you have to free in C++ and vice versa.
C++ memory magnament is based on RAII. That means that destructors are called when the lifetime of a variable ends.
For example:
class Foo
{
public:
Foo() { cout << "Constructor!!!" << endl; }
~ Foo() { cout << "Destructor!!!" << endl; }
};
int main()
{
Foo my_foo_instance;
}
Prints:
Constructor!!!
Destructor!!!
Because the constructor is called in the initiallization of my_foo_instance (At the declaration), and the destructor is called when the lifetime of my_foo_instanceends (That is, at the end of main() ).
Also, this rules works for any context, including class attributes:
class Foo1
{
public:
Foo1() { cout << "Foo1 constructor!!!" << endl; }
~ Foo1() { cout << "Foo1 destructor!!!" << endl; }
};
class Foo2
{
private:
Foo1 foo1_attribute;
public:
Foo2() { cout << "Foo2 constructor!!!" << endl; }
~ Foo2() { cout << "Foo2 destructor!!!" << endl; }
};
int main()
{
Foo2 my_foo2_instance;
}
Prints:
Foo1 constructor!!!
Foo2 constructor!!!
Foo2 destructor!!!
Foo1 destructor!!!
The trace of the program is:
Main starts
Initiallization of my_foo2_instance: Call to Foo2 constructor
First of all, Foo2 initializes its attributes: Call to Foo1 constructor
Foo1 has no attributes, so Foo1 executes its constructor body: cout << "Foo1 constructor" << endl;
After attributes initiallization, Foo2 executes its constructor body: cout << "Foo2 constructor" << endl;
End of main scope, so end of my_foo2_instance lifetime: Call to Foo2 destructor
Foo2 destructor executes its body: cout << "Foo2 destructor" << endl;
After the destructor, the lifetime of the attributes of Foo2 ends. So: Call to Foo1 destructor
Foo1 destructor executes its body: cout << "Foo1 destructor" << endl;
After the destructor, the lifetime of the attributes of Foo1 ends. But Foo1 has no attributes.
But what you forget is that a pointer its a basic type, so it has no destructor. To destroy the object pointed by the pointer (Thats is, finallize the life of the pointee object), use use delete operator in destructor body.
Destructor never deallocates anything on its own accord. Destructor will only implicitly call destructors for class subobjects and execute whatever code you put into the destructor's body. Since in your case the subobject ch is of raw pointer type, it has no destructor. So nothing will be done in your case. Since it is you who allocated the memory, it is you who's responsible for deallocating it. In short, yes, you do need that delete[] ch in your destructor.
If you want that memory deallocated automatically, use a smart pointer class instead of a raw pointer. In that case the destructor of your class will automatically call the destructor of the smart pointer subobject, which will deallocate memory for you. In your specific example an even better idea would be to use std::string to store the string inside the class object.
The heap corription in your case is caused by the fact that you allocate insufficient memory for your string, which leads to an out-of-bounds write in strcpy. It should be
ch = new char[strlen(_ch) + 1];
strcpy(ch,_ch);
The extra space is needed for the terminating zero character.
My take:
1) The short answer is no.
2) As for "why not", consider the following example:
cls create()
{
cls Foo("hello"); // This allocates storage for "ch"
return Foo;
} // Return variable is by value, so Foo is shollow-copied (pointer "ch" is copied).
// Foo goes out of scope at end of function, so it is destroyed.
// Do you want member variable "ch" of Foo to be deallocated? Certainly not!
// Because this would affect your returned instance as well!
Recommendations:
If you want to see whether your code leaks storage, you may use an excellent tool valgrind, http://valgrind.org/
As for what to read to understand this topic better, I would recommend the standard C++ literature, plus have a look at smart pointers, e.g. unique pointer
http://www.cplusplus.com/reference/memory/unique_ptr/
which will help you understand the topic and everything will be put to place.