You don't
need to do anything in a class's destructor. That's just the way C++ works. However just because something's legal in the language doesn't mean you
should do it.
Generally you
should to do something in your destructors when:
- The object holds the last reference to a dynamically allocated object (you should
delete
it) whether it was allocated in an object's constructor or not [1].
- You object manages a resource (you should do whatever it takes to cleanly return the resource back where it came)
So if we rewrite your question a bit more specifically:
"If in class A's constructor we dynamically create objects of another class, B, then
should we delete the objects of class B in class A's destructor?"
The answer is "Yes, unless the object of class A has passed ownership (a reference to the object of class B) to something else." [1]
The principle at work here is ownership - when an object A is responsible for managing the lifetime of object B "A owns B." This ownership can come from:
- B being a member of A's class [2]
- B being dynamically allocated by A
- A being given a reference to B
Oh, and be careful - it's hard to tell whether a class owns an instance of another one if your code uses pointers
class A
{
public:
A();
~A();
private:
B *b_; };
you can't tell whether ownership is occurring or not [3].
[1] Another, better, answer is "You never write
delete
. As soon as you dynamically create an object assign the pointer to the object to a pointer like object." Pointer like objects include unique_ptr, shared_ptr and vector - all means to reach object lifetime Nirvana.
Also you're a real mug if you use
delete
in your programs.
[2] This is an interesting one, 'cause if B is a member of A then A owns B and there's no way of giving ownership of B away - B is a part of A and you can't chop it out. You can't make a decision about when A gets rid of B - it just happens. When A goes to the bit-bucket in the sky then so does B.
[3] Which is where smart pointers come in... yay! As soon as you embrace smart pointers your code says more about it's intent. If you write your class like this:
class A
{
public:
A();
~A();
private:
std::unique_ptr b_;
};
then you tell the reader than objects of class A own b_ as std::unique_ptr effectively converts a dynamically allocated object into an "ordinary" member. When objects of class A die, they take whatever b_'s pointing to with them.