Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why must I declare copy & move constructors when declaring destructors?

I have a NonCopyable class and an Application class derived from NonCopyable:

class NonCopyable
{
public:
    NonCopyable() = default;
    virtual ~NonCopyable() = default;
    NonCopyable(NonCopyable const&) = delete;
    NonCopyable& operator =(NonCopyable const&) = delete;
    NonCopyable(NonCopyable&&) = delete;
    NonCopyable& operator=(NonCopyable&&) = delete;
};

class Application : public NonCopyable
{
public:
    ~Application() { /* ...delete stuff... */ }
};

As you see, I don't need to redeclare deleted move constructors or assignment operators as I've declared them in the base class. But why does Resharper suggest me to declare other special member functions? It said:

Class Application defines a non-default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator [hicpp-special-member-functions].

There're also [cppcoreguidelines-special-member-functions] reminders with the same message.

The current workaround is to explicitly write all of them to make the warning go away:

class Application : public NonCopyable
{
public:
    ~Application() { /* ...delete stuff... */ }
    Application(Application const&) = delete;
    Application& operator =(Application const&) = delete;
    Application(Application&&) = delete;
    Application& operator=(Application&&) = delete;
};
like image 626
MiP Avatar asked Jan 24 '18 12:01

MiP


People also ask

Why do we need copy?

It entertains the readers, resonates with them but also compels them to take action. Good copy gives you the opportunity to promote your products in a highly effective manner in front of a vast audience that is ready to listen to what you have to say.

Why do you need a copy constructor?

A user-defined copy constructor is generally needed when an object owns pointers or non-shareable references, such as to a file, in which case a destructor and an assignment operator should also be written (see Rule of three).

What is the purpose of a copy assignment operator?

A trivial copy assignment operator makes a copy of the object representation as if by std::memmove. All data types compatible with the C language (POD types) are trivially copy-assignable.

Why do we need copy constructor in Java?

A copy constructor in a Java class is a constructor that creates an object using another object of the same Java class. That's helpful when we want to copy a complex object that has several fields, or when we want to make a deep copy of an existing object.

What happens if you don't declare a copy constructor?

If you don't declare a copy constructor, the compiler generates a member-wise copy constructor for you. Similarly, if you don't declare a copy assignment operator, the compiler generates a member-wise copy assignment operator for you. Declaring a copy constructor doesn't suppress the compiler-generated copy assignment operator, and vice-versa.

Why can’t I copy and paste?

Some factors like issues with the keyboard or a full clipboard can cause the copy and paste function to not work. So, let’s discover more causes why the copy and paste function not working and fixes to address it accordingly. Why Can’t I Copy Paste? How to Fix It? How to Fix Copy-paste Issues in Specific Programs?

What is the use of copy constructor?

A copy constructor is called when an object is passed by value. Copy constructor itself is a function. So if we pass an argument by value in a copy constructor, a call to copy constructor would be made to call copy constructor which becomes a non-terminating...

Is deep copy possible with user defined copy constructor?

Deep copy is possible only with user defined copy constructor. In user defined copy constructor, we make sure that pointers (or references) of copied object point to new memory locations. Which of the following two statements call copy constructor and which one calls assignment operator?


Video Answer


2 Answers

default, delete are not inherited

You are wrongfully assuming some kind of transitivity (When constructing an object, I always need to use the superclass constructor with a similar signature).

Here is a counter-example :

#include <string>
#include <iostream>

class NonCopyable
{
public:
    NonCopyable() = default; // Added this little fella
    virtual ~NonCopyable() = default;
    NonCopyable(const NonCopyable &) = delete;
    NonCopyable& operator =(NonCopyable const&) = delete;
    NonCopyable(NonCopyable&&) = delete;
    NonCopyable& operator=(NonCopyable&&) = delete;
};

class Application : public NonCopyable
{
public:
    Application() = default;
    Application(const Application& a) : NonCopyable(), x(a.x){}
    ~Application() { /* ...delete stuff... */ }
    std::string x;
};

int main(){
   Application a;
   a.x = "Hello";
   Application b(a);

   std::cout << b.x << std::endl;

}

As you can see I am perfectly able to declare copy constructor of a subclass by using the only available constructor of the superclass. I could also declare the other constructors of the rule of 5. This is why static analyzers are giving warning about the rule of 5 .

Conclusion : NonCopyable is a useless class.

like image 192
UmNyobe Avatar answered Oct 26 '22 07:10

UmNyobe


More often than not, if a class defines a destructor that differs from what the compiler would automatically generate, its purpose is to release some resource that is managed by the class.

If there is some resource that a destructor must release then there is usually also a need for a user-defined constructor to initialise that resource, a user-defined copy constructor to create a copy of the resource owned by an existing object of the same type, and a user-defined move constructor to assume ownership of the resource from a temporary object that is ceasing to exist.

Similarly, there will also be a need for an copy assignment operator and move assignment operator, so that expressions like a = b will work to copy or move the resource to an existing objects.

If the class does not have one or more of these constructors or assignment operators then, practically, code which uses several objects often will not behave consistently (e.g. a destructor releasing a resource twice because it is shared by two objects, resulting in undefined behaviour, etc).

Of course, there are circumstances in which a class does not need the complete set of constructors, assignment operators, and destructor. However, leaving one of them out is often a programmer error (as distinct from an intended effect) so code analysis tools will often complain about such cases.

like image 25
Peter Avatar answered Oct 26 '22 08:10

Peter