Warning: definition of implicit copy constructor is deprecated

前端 未结 3 1268
终归单人心
终归单人心 2020-12-25 13:20

I have a warning in my C++11 code that I would like to fix correctly but I don\'t really know how. I have created my own exception class that is derived from std::runt

相关标签:
3条回答
  • 2020-12-25 13:41

    You do not need to explicitly declare the destructor in a derived class:

    § 15.4 Destructors [class.dtor] (emphasis mine)

    A destructor can be declared virtual (13.3) or pure virtual (13.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.

    In fact, it might even be detrimental to performance in some cases, as explicitly declaring a destructor will prevent the implicit generation of a move constructor and move assignment operator.

    Unless you need to do something in your destructor, the best course of action would be to just omit an explicit declaration of a destructor.

    If you do need a custom destructor, and are certain that the default copy ctor, copy assignment operator, move ctor and move assignment operator would do the correct thing for you, it is best to explicitly default them like so:

    MyError(const MyError&) = default;
    MyError(MyError&&) = default;
    MyError& operator=(const MyError&) = default;
    MyError& operator=(MyError&&) = default;
    

    Some reasoning on why you're seeing the error, because this used to be perfeclty valid code in C++98:

    As of C++11, implicit generation of the copy constructor is declared as deprecated.

    § D.2 Implicit declaration of copy functions [depr.impldec]

    The implicit definition of a copy constructor as defaulted is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. The implicit definition of a copy assignment operator as defaulted is deprecated if the class has a user-declared copy constructor or a user-declared destructor (15.4, 15.8). In a future revision of this International Standard, these implicit definitions could become deleted (11.4).

    The rationale behind this text is the well-known Rule of three.

    All quotes below are sourced from cppreference.com: https://en.cppreference.com/w/cpp/language/rule_of_three

    Rule of Three

    If a class requires a user-defined destructor, a user-defined copy constructor, or a user-defined copy assignment operator, it almost certainly requires all three.

    The reason why this rule of thumb exists is because the default generated dtor, copy ctor and assignment operator for handling different types of resources (most notably pointers to memory, but also others, like file descriptors and network sockets to name just a couple) rarely do the correct behaviour. If the programmer thought that he needed special handling for the closing of a file handle in the class destructor, he most surely wants to define how this class should be copied or moved.

    For completeness, below are the often related Rule of 5, and the somewhat disputed Rule of Zero

    Rule of Five

    Because the presence of a user-defined destructor, copy-constructor, or copy-assignment operator prevents implicit definition of the move constructor and the move assignment operator, any class for which move semantics are desirable, has to declare all five special member functions:

    Rule of Zero

    Classes that have custom destructors, copy/move constructors or copy/move assignment operators should deal exclusively with ownership (which follows from the Single Responsibility Principle). Other classes should not have custom destructors, copy/move constructors or copy/move assignment operators.

    0 讨论(0)
  • 2020-12-25 13:41

    Note: the same happens for much different code but I'm writing it here in case someone gets the same warning.

    There was a bug in GCC versions 6.4 - 9.0 where using declarations for base_type's operator= and base_type's ctor in types inheritted from base_type which was a class template did not actually created copy/move ctor/operators (ending in very unexpected compiler errors that an object can not be copied/moved).

    Since GCC 9.0, the bug is fixed but it creates this warning instead. The warning is wrong and should not appear (the using explicitly declares constructors/operators).

    • Example code with workarounds and GCC version comparison: https://godbolt.org/z/WgIH4c
    • GCC bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89381
    • another GCC bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92145
    • Origin of this discovery: https://github.com/boostorg/spirit/issues/465
    0 讨论(0)
  • 2020-12-25 13:46

    Now I could get rid of that warning by simply removing the virtual destructor but I always thought that derived classes should have virtual destructors if the base class (in this case std::runtime_error) has a virtual destructor.

    You thought wrong. Derived classes will always have virtual destructor if you define one in base, no matter if you create it explicitly or not. So removing destructor would be simplest solution. As you can see in documentation for std::runtime_exception it does not provide it's own destructor either and it is compiler generated because base class std::exception does have virtual dtor.

    But in case you do need destructor you can explicitly add compiler generated copy ctor:

    MyError( const MyError & ) = default;
    

    or prohibit it making class not copyable:

    MyError( const MyError & ) = delete;
    

    the same for assignment operator.

    0 讨论(0)
提交回复
热议问题