I read that destructors need to be defined when we have pointer members and when we define a base class, but I am not sure if I completely understand. One of the things I am not sure about is whether or not defining a default constructor is useless or not, since we are always given a default constructor by default. Also, I am not sure if we need to define default constructor to implement the RAII principle (do we just need to put resource allocation in a constructor and not define any destructor?).
class A { public: ~Account() { delete [] brandname; delete b; //do we need to define it? }; something(){} =0; //virtual function (reason #1: base class) private: char *brandname; //c-style string, which is a pointer member (reason #2: has a pointer member) B* b; //instance of class B, which is a pointer member (reason #2) vector<B*> vec; //what about this? } class B: public A { public something() { cout << "nothing" << endl; } //in all other cases we don't need to define the destructor, nor declare it? }
You only need to define a custom destructor when the class stores handles to system resources that need to be released, or pointers that own the memory they point to. In the preceding example, the destructor String::~String uses the delete operator to deallocate the space dynamically allocated for text storage.
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.
The constructor code is the construction of t1. Then a copy constructor is used when it is pushed back on the vector. When the clear() is called, it calls the destructor for the object in the vector. Then t1's destructor is called when it goes out of scope.
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.
The good ol' way of handling resources was with the Rule of Three (now Rule of Five due to move semantic), but recently another rule is taking over: the Rule of Zero.
The idea, but you should really read the article, is that resource management should be left to other specific classes.
On this regard the standard library provides a nice set of tools like: std::vector
, std::string
, std::unique_ptr
and std::shared_ptr
, effectively removing the need for custom destructors, move/copy constructors, move/copy assignment and default constructors.
In your code you have a lot of different resources, and this makes for a great example.
If you notice brandname
is effectively a "dynamic string", the standard library not only saves you from C-style string, but automatically manages the memory of the string with std::string
.
The second resource appears to be a dynamically allocated B
. If you are dynamically allocating for other reasons other than "I want an optional member" you should definitely use std::unique_ptr
that will take care of the resource (deallocating when appropriate) automatically. On the other hand, if you want it to be an optional member you can use std::optional
instead.
The last resource is just an array of B
s. That is easily managed with an std::vector
. The standard library allows you to choose from a variety of different containers for your different needs; Just to mention some of them: std::deque
, std::list
and std::array
.
To add all the suggestions up, you would end up with:
class A { private: std::string brandname; std::unique_ptr<B> b; std::vector<B> vec; public: virtual void something(){} = 0; };
Which is both safe and readable.
As @nonsensickle points out, the questions is too broad... so I'm gonna try to tackle it with everything I know...
The first reason to re define the destructor would be in The Rule of Three which is on part the item 6 in Scott Meyers Effective C++ but not entirely. The rule of three says that if you re defined the destructor, copy constructor, or copy assignment operations then that means you should rewrite all three of them. The reason is that if you had to rewrite your own version for one, then the compiler defaults will no longer be valid for the rest.
Another example would be the one pointed out by Scott Meyers in Effective C++
When you try to delete a derived class object through a base class pointer and the base class has a non virtual destructor, the results are undefined.
And then he continues
If a class does not contain any virtual functions, that is often an indication that it is not meant to be used as a base class. When a class is not intended to be used as a base class, making the destructor virtual is usually a bad idea.
His conclusion on destructors for virtual is
The bottom line is that gratuitously declaring all destructors virtual is just as wrong as never declaring them virtual. In fact, many people summarize the situation this way: declare a virtual destructor in a class if and only if that class contains at least one virtual function.
And if it is not a Rule Of three case, then maybe you have a pointer member inside your object, and maybe you allocated memory to it inside your object, then, you need to manage that memory in the destructor, this is item 6 on his book
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With