Sunday 15 October 2017

c++ - When do we need to define destructors?





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?
}

class="post-text" itemprop="text">
class="normal">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 rel="noreferrer">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 rel="noreferrer">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 rel="noreferrer">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 href="http://en.cppreference.com/w/cpp/experimental/optional"
rel="noreferrer">std::optional
instead.




The collection of
Bs



The last resource is just an array of
Bs. That is easily managed with an href="http://en.cppreference.com/w/cpp/container/vector"
rel="noreferrer">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: href="http://en.cppreference.com/w/cpp/container/deque"
rel="noreferrer">std::deque, href="http://en.cppreference.com/w/cpp/container/list"
rel="noreferrer">std::list and href="http://en.cppreference.com/w/cpp/container/array"
rel="noreferrer">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

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...