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 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?
}
Answer
The rule of Three and The Rule of Zero
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.
How to apply it to your code
In your code you have a lot of different resources, and this makes for a great example.
The string
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 dynamically allocated B
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 collection of Bs
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
.
Conclusion
To add all the suggestions up, you would end up with:
class A {
private:
std::string brandname;
std::unique_ptr b;
std::vector vec;
public:
virtual void something(){} = 0;
};
Which is both safe and readable.
No comments:
Post a Comment