how much does the default destructor do - c++

Does the default destructor in C++ classes automatically delete members that are not explicitly allocated in code? For example:
class C {
public:
C() {}
int arr[100];
};
int main(void) {
C* myC = new C();
delete myC;
return 0;
}
Does delete myC deallocate myC's arr automatically? Or do I need to write C's destructor to do this explicitly?

The constructor (in the absence of any ctor-initializer-list) calls the default constructor for each subobject.
Since you have no base classes and your member variables are primitive types, it will do nothing at all.
Same with the destructor. Yours is implicitly compiler-generated since you haven't declared one, and it will call the destructor for each subobject. Again that's trivial because your only subobject is an aggregate of primitives.
Now, all memory of the class will be freed when you delete it. Since the array is embedded inside the class, it's part of the same memory region and will be freed at the same time.

The implicitly defined (default) destructor will call the destructor for each member. In the case of a member array, it will call the destructor for each element of the array.
Note that pointers don't have destructors; you need to manually delete them. You don't have this problem in the provided example, but it's something to be aware of.

If your class/struct contains a pointer, and you explicitly allocate something for that pointer to refer to, then you normally need to write a matching delete in the dtor. Members that are directly embedded into the class/struct will be created and destroyed automatically.
class X {
int x;
int *y;
public:
X() : y(new int) {}
~X() : { delete y; }
};
Here X::x will be created/destroyed automatically. X::y (or, to be technically correct, what X::y points at) will not -- we allocate it in the ctor and destroy it in the dtor.

Anything that you call new for must have a corresponding delete. If you didn't call new to create an instance of something then you don't have to call delete.

You don't have to write a destructor. C++ class has the default destructor to delete the object after 'return 0' to recycle the memory.

Related

Default destructor when using pointer to base class

class A
{
int a;
};
class B : public A
{
int b;
};
int main(void)
{
A * p = new B;
delete p; // (1)
return 0;
}
In the above code both classes have default compiler-generated destructors. Both classes also have only Plain Old Data as members so I don't need manually written d'tors which would free any resources. So my question is - after the call in (1) will the default destructor free the entirety of B's instance or will there be any memory leaks? I know that I could use a virtual destructor here but I'm not sure how default d'tors behave.
What you are trying to do invokes undefined behavior, so declaring A destructor as virtual can be considered mandatory.
delete p
Will try to delete p as an instance of A but since the destructor is not declared virtual the correct runtime implementation is not called.
Mind that this doesn't happen when you don't have a pointer but just a concrete object, eg
A a = B();
Because object slicing occurs before, so when a exits the scope it's just an A

Is it dangerous to use placement new on an old object without explicitly calling the destructor first?

I would like to recycle memory for an object rather than deallocating and reconstructing it. Is the following usage of "placement new" safe, assuming that Foo in practice does not contain pointers (but might contain functions)?
Also, is the final delete call safe, and will it correctly call the destructor on the second "new" object, and correctly free the memory afterwards?
#include <new>
struct Foo {
int hello;
int world;
};
int main() {
Foo* foo = new Foo;
// Do something with foo
// Done with foo, writing a new version of foo on top of the old one.
new(foo) Foo();
delete(foo);
}
The simple example above compiles and runs without errors, but I cannot tell by running it whether it might blow up for some reason in a more complex environment.
It's safe because the object you're overwriting has a trivial destructor. From n3337, chapter 3.8 (Object lifetime):
4 A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly
calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type
with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage
which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a
delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and
any program that depends on the side effects produced by the destructor has undefined behavior.
The delete call is safe, too. You're calling it on a pointer that you got from new and there's a live object at that place.
And as you hinted in the question, it could invoke undefined behaviour if the destructor is non-trivial and has side effects - you need to call it explicitly in that case. Whether or not the class contains pointers is not directly important - reusing the storage is safe even in that case, but of course, you could introduce memory leaks and other bugs that way.
No, it is not dangerous to reuse memory of an object, provided that you are doing it correctly. Moreover, you do not have to restrict yourself to objects that have no pointers: by calling the destructor explicitly you can prepare the object for reuse, like this:
Foo* foo = new Foo;
// Do something with foo
// Done with foo, writing a new version of foo on top of the old one.
foo->~Foo(); // Call the destructor explicitly to clean up the resources of a Foo
new(foo) Foo(); // Place new data into the previously allocated memory
delete(foo); // We are deleting a fully initialized object, so it is OK
There have been two answers already, but they give, I fear, an incomplete picture.
You may reuse the storage of an object, providing that you respect a few conditions:
You need not use a dynamically allocated object, any object is fine.
You should properly destroy the previous object, by calling its destructor (explicitly); failure to do so leads to undefined behavior if the destructor has side-effects (see §3.8/4)
The object that you place should have the same dynamic type as the previous object (see §3.8/7)
Let us review them, starting with any object is fine:
struct Foo {
int hello;
int world;
};
void automatically_allocated() {
Foo foo;
foo.~Foo();
new (&foo) Foo{};
}
void dynamically_allocated() {
std::unique_ptr<Foo> foo(new Foo{});
foo->~Foo();
new (&*foo) Foo{};
}
Let use continue with destroy the previous object:
struct Bar {
int hello;
std::string world;
};
void UNDEFINED_BEHAVIOR() {
Bar bar;
new (&bar) Bar{}; // most likely scenario: leaks memory owned by bar.world
}
And finally with same dynamic type:
struct Base { virtual ~Base() {} };
struct Derived: Base { std::string world; };
struct Other: Base { int hello; }
void UNDEFINED_BEHAVIOR() {
Derived derived;
Base& b = derived;
b.~Base(); // fine
new (&b) Other{};
// Most likely here, calls "derived.~Derived()" on an object of type Other...
}

Destructor's functionalities

For a simple class like this:
class X {
public:
//...
private:
int *ptr;
};
X::~X() {
delete ptr;
}
I have written a destructor to free the memory pointed to by ptr. Now, I am wondering, if my destructor stays like this, when is ptr actually destroyed?
Thanks
I think this article might answer most of your questions
"Destructors are implicitly called when an automatic object (a local
object that has been declared auto or register, or not declared as
static or extern) or temporary object passes out of scope. They are
implicitly called at program termination for constructed external and
static objects. Destructors are invoked when you use the delete
operator for objects created with the new operator."
More specifically:
"The destructors of base classes and members are called in the reverse
order of the completion of their constructor:
The destructor for a class object is called before destructors for
members and bases are called.
Destructors for nonstatic members are called before destructors for
base classes are called.
Destructors for nonvirtual base classes are called before destructors
for virtual base classes are called."
delete invokes the destructor of the object that is being deleted and then frees the memory it occupied.
The destructor will calls in the end of scope where the specific instance are.
The local version of ptr for a given instance of X will be destroyed when the object goes out of scope. For example:
int main()
{
X obj;
for (int i=0; i<10; i++) {
X tmp;
// do work with tmp
...
// tmp goes out of scope here
// the destructor tmp::~X will be called here, immediately after each iteration ends
}
// obj goes out of scope here
// the destructor obj::~X called when the program ends
}

Deallocation of a vector in C++ [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
deleting dynamically allocated object that contains vector in C++ STL
I have a struct like this
struct foo {
vector<int> myvector;
};
Now, I create a pointer to foo, resize and insert some elements into the vector.
foo *myfoo = new foo;
myfoo->myvector.resize(100);
myfoo->myvector.push_back(0);
myfoo->myvector.push_back(1);
... // and so on
Now, before myfoo goes out of scope, I would have to deallocate the memory allocated to it with
delete myfoo;
My question is whether this would take care freeing myvector also? I have this particular query because now that myvector is resized, the STL library would presumably allocated the container in the heap. So, when I free up myfoo, I wouldn't want the memory allocated to myvector leaking.
Yes, deleting myfoo will destroy all of its members too, which includes the std::vector. It's important to note that if you had pointers inside foo, only the pointers would be destroyed, not the objects they point to (unless of course you defined a destructor that did that job for you - which you should!).
It is mandated by the standard that after execution of the destructor, any non-static data members are destroyed also (§12.4/8):
After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X's direct non-variant non-static data members, the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X's virtual base classes.
The class foo has a defaulted destructor because no user-declared destructor is defined (§12.4/4):
If a class has no user-declared destructor, a destructor is implicitly declared as defaulted (8.4).
The destructor of myfoo is called when it is deleted (§5.3.5/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.
A delete-expression is an expression of the form:
::opt delete cast-expression
Calling delete foo will deallocate and call destructors (if applicable) on all members of foo, so yes. If it didn't work this way the language would be much more difficult to use.
The struct foo just holds the container of a vector. The items of the vector are allocated separately (usually on the heap) anyway.
The vector's destructor deletes the actual vector on the heap, and the vector is destroyed when the object is deleted.
Here is code example that answers your question.
#include <iostream>
struct bar {
~bar() {std::cout << "deleted bar" << std::endl;}
};
struct foo {
bar b[10];
};
int main() {
foo* f = new foo();
delete f;
}
The program will print "deleted bar" 10 times.

Base class's destructor called without destroying the base class!

#include<iostream>
using namespace std;
class A
{
public:
int i;
A() {cout<<"A()"<<endl;}
~A() {cout<<"~A()"<<endl;}
};
class B:public A
{
public:
int j;
B(): j(10)
{
this->i=20;
this->~A();
}
};
int main()
{
B abc;
cout<<"i="<<abc.i<<" j="<<abc.j<<endl;
}//main
Two questions:
How come A's destructor gets called like an ordinary function instead of destroying the object? (or is it some kind of rule that the base class will be destroyed only if the child class's destructor calls the base class's destructor?) I was trying out this sample code to find out how the destructor works. So if simply calling the destructor function does not destruct the object, then there is obviously some other kind of call that calls the destructor and only then the object is destructed. What's so special in that kind of call and what call is it?
Is there a way to have an initialization list for A in B's constructor? Something like this:
class B:public A
{
B(): j(10), A():i(20) {}
};
Destructor is like any other normal function which you can call (but you should never do it unless you use a placement new). When you call delete on a object two things happen: Destructor is called for cleanup and then operator delete is called to release the memory allocated for the object. Here the second step is not happening.
No, you can not call it like that. What you can do is some thing like this:
class A
{
public:
A(int n) : i(n){}
};
class B : public A
{
public:
B() : A(20), j(10){}
};
The base class's destructor should be virtual. Here, as it's created on the stack, it's not problem, but anyway..
No, but you can call the class A() constructor in the initialize list of B's constructor, like this:
B(): A( .. ), ...
A* a = new B();
//..
delete a;
will not call B's destructor unless class A destructor is virtual. That's why STL containers should not be derived - theirs destructors are not virtual.
#Nav: no, your understanding of "destroyed" is just wrong. When an object's destructor is called, the object is destroyed. You seem to believe that the memory it resided in evaporates entirely, but that never happens. The object no longer exists, but some garbage data is typically left over by the object, and if you're willing to break the rules of C++ and invoke undefined behavior, then you can read those leftover bytes, and they'll look like the object, and because there are no runtime checks on whether you're accessing a valid object, you can often treat them as an object. Which you do.
It's illegal, it's undefined behavior, but in practice it often works.
Once again, a destructor does not physically vaporize the memory. Your RAM still has the same capacity after a destructor has executed. Conceptually, the object no longer exists once the destructor has run. But the data it contained is still there in memory.
For point:
This is an undefined behaviour but only ~A() is called though an instance of class B because ~A() is not declared virtual. See more on Wikipedia.
No. For derived classes, first call your parent class, then assign parameters.
For point 1) on Wikipedia:
having no virtual destructor, while
deleting an instance of class B will
correctly call destructors for both B
and A if the object is deleted as an
instance of B, an instance of B
deleted via a pointer to its base
class A will produce undefined
behaviour.
Example (for point 2):
B(): A(), j(10) {}
or
B(): A() {j = 10;}
1) Destructor calling order in C++ is reverse order of the constructor calling order. So first derived class object get destroy and then base class object.
2) No.
In the code that you are giving, you are indeed destroying the base class and as such i. Calling a destructor and then using the dead object is undefined behavior - it may work or it may crash.
Should i was something that is more complex that an int (for example a vector), trying to do anything with that would probably result in a crash.
If you call ~SomeClass() yourself, explicitly, the destructor function will be called. Which leaves the object (in this case, the base class part of the object) in a destroyed state.
Since the destructor is not virtual, the destructor of derived classes will not be called, but base classes of SomeClass will be destroyed too.
Trying to find out if A is really destroyed by just using the i member, is not a good test. In fact, you can't test this, since using the object results in undefined behavour. It may work, or it may not (in your case, it probably will print "i=20 j=10", but i is already destroyed).