2

In my Qt project I have a class like below. I get the following warning (understood), and add a virtual dtor.

dbmappingcomponentaware.h:25: warning: CDbMappingComponentAware has virtual functions but non-virtual destructor

Now I get

warning: definition of implicit copy assignment operator for 'CDbMappingComponentAware' is deprecated because it has a user-declared destructor

The class is a plain vanilla class and I have not declared any operators. How would I resolve that conflict?

As of How to disable implicitly-defined copy constructor generation when there is user defined destructor it looks like I have to accept the "deprecated" warning, but I am not sure.

Code snippet:

//! Allows subcomponents to gain access to model component
class CDbMappingComponentAware {
  public:
    //! Destructor (added for 1st warning)
    // virtual ~CDbMappingComponentAware() {}

    //! Set the corresponding component
    virtual void setMappingComponent(CDbMappingComponent *component);
...
...

-- Edit, based on comment --

Reading https://en.cppreference.com/w/cpp/language/copy_assignment it says,

The generation of the implicitly-defined copy assignment operator is deprecated(since C++11) if T has a user-declared destructor or user-declared copy constructor.

But why is that? I mean, why is the dtor affecting the copy operator?

Horst Walter
  • 13,663
  • 32
  • 126
  • 228
  • 7
    I *guess* you could just explicitly declare them `= default` (or `= delete`) to shut the compiler up. Being explicit is usually a good thing regardless of compiler warnings btw. – Jesper Juhl Aug 22 '18 at 16:41
  • But would that not mean I cannot copy a object if I define a virtual dtor (unless I explicitly write a copy assignment operator). Why would that make sense? – Horst Walter Aug 22 '18 at 17:22
  • 3
    Related: https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three – HerrJoebob Aug 22 '18 at 17:51
  • Are you saying the warning is there to enforce the rule of three? As I do not deal with resources the rule of three does not make really sense here. As I remember it the rule is a guideline, not a must. Still not really understand what the warning means by `deprecated` in that very scenario. Also wonder why that is new since C++11. But good hint! – Horst Walter Aug 22 '18 at 18:02

1 Answers1

2

As of How to disable implicitly-defined copy constructor generation when there is user defined destructor it looks like I have to accept the "deprecated" warning, but I am not sure.

You don't have to accept the "deprecated" warning. You have 3 options here, implement the operator, explicit default the operator or delete the operator.

First of all, this warning is trigger because you actually use the copy assignment operator somewhere. Maybe not even on purpose (see //unfortunate mistake in the example below). You should actually get a note in addition to the warning where you use the operator, something like:

note: in implicit copy assignment operator for 'CDbMappingComponentAware' first required here

Consider the following example (running version):

class foo {
public:
    virtual ~foo() {}

    // options
    // implement
    //foo& operator=(foo const&) {return *this;}
    // default
    //foo& operator=(foo const&) = default;
    // delete
    //foo& operator=(foo const&) = delete;
};

class bar : public foo {
public:
    ~bar() override {};
};

// stupid mistake... should be defined
// void fn(bar const&)
void fn(bar) {}


int main(int, char*[]) {
    foo* f1 = new bar;
    foo* f2 = new bar;

    // triggers warning
    *f1 = *f2;

    // unfortunate mistake
    bar b;
    // triggers warning twice since bar inherits from foo
    fn(b);

    return 0;
}

In the case, you are really using the copy assignment operator, you should either implement it, or default it if it is really plain vanilla. See below why you eventually should not default it. If you don't want to be able to copy the instance at all, delete the operator/ctor.

By the way, it is the same for copy constructor, not only assignment operator. It is described in §15.8.1/6 for copy constructor and §15.8.2/2 for copy assignment operator in the draft n4727.

However:

But would that not mean I cannot copy a object if I define a virtual dtor (unless I explicitly write a copy assignment operator).

No, you can still use the generated copy ctor/assignment as long as it is a warning. Depreacated means it will (probably) become an error in the future (in case of C++ maybe in about 40 years or more, if at all). So if you don't want your code to spit this warning as an error, when it is not supported by the compiler anymore, you should fix it now.


But why is that? I mean, why is the dtor affecting the copy operator?

Hypothetical answer here:

One purpose I can think of, is to prevent some mistakes. Consider the example (taken from Why doesn’t my constructor work right? ):

class Handle {
private:
    string name;
    X* p;
public:
    Handle(string n)
        :name(n), p(0) { /* acquire X called "name" and let p point to it */ }
    ~Handle() { delete p; /* release X called "name" */ }
};
void f(const string& hh)
{
    Handle h1(hh);
    Handle h2 = h1; // leads to disaster!
}

Here, the default copy gives us h2.name==h1.name and h2.p==h1.p. This leads to disaster: when we exit f() the destructors for h1 and h2 are invoked and the object pointed to by h1.p and h2.p is deleted twice.

To prevent the double deletion, you have to be explicit and not rely on the generated/ defaulted copy constructor/assignment.

Are you saying the warning is there to enforce the rule of three?

In this particular case: Yes, I would say so.

As I do not deal with resources the rule of three does not make really sense here.

This would require the compiler to take the members in account. Pretty much effort for such an unmature warning.

Personal thoughts:

IMHO, I do not belive this will ever become an error in C++. There is way to much code out there, relying on the auto-generated ctor/assignment. Making this an error would break (literally) tousands of projects. -> Not going to happen...

user1810087
  • 5,146
  • 1
  • 41
  • 76