0
votes

Consider a base class wich prevent copy construction and copy assignement like this:

class NonCopyable {
    public:
        NonCopyable() = default;
        ~NonCopyable() = default;

        NonCopyable(NonCopyable const&)                 = delete;
        NonCopyable& operator=(NonCopyable const&)      = delete;
};

Our developers can now include this class, and use it to disable copy for inherited classes, like this:

class CopyTest : public NonCopyable {
    public:
        CopyTest() {
            std::cout << "copy test created" << std::endl;
        }

        ~CopyTest() {
            std::cout << "copy test deleted" << std::endl;
        }
};

When I try to use the CopyTest class:

CopyTest ct, ct1(ct);

or

CopyTest ct;
CopyTest ct1 = ct2;

The compiler emit an error : use of deleted function xxx (where xxx is my deleted copy ctor, or copy operator)

Then, if I want to std::move a CopyTest object :

CopyTest ct;
CopyTest ct1 = std::move(ct);

The compiler emit the same error (use of deleted function xxx - where xxx remains my copy ctor or assignement operator).

If I remind correctly, it's because the developer has not defined the proper move ctor/assignement operator.

Is it possible to force the compiler to tell the developper of the CopyTest class that the move error is here because he has not defined the proper move ctor/assignement operator, and not because the copy ctor/assignement operator is deleted on the base class?

Platform :

Debian 9

GCC 6.3.0

Compilation flags :

-fpermissive -ggdb -std=c++11

2
Any good developer will know that the probable cause of this error is the lack of a move constructor (He is using std::move, after all). I wouldn't worry about it.Cássio Renan
I agree with you, but I don't want to rely on other people nor my probable skills, and thought that an exact compiler error was easier to be understood by beginners like me...Ayak973
The compiler error is exact: the implicitly defined move constructor is deleted, because the copy ctor is.Walter

2 Answers

2
votes

add

    NonCopyable(NonCopyable &&)                 = delete;
    NonCopyable& operator=(NonCopyable &&)      = delete;

that now complains about the base class move ctor being deleted.

0
votes

Formally speaking, the implicitly generated move ctor/assignment is defined as "deleted" in the base class NonCopyable itself. A "deleted" move ctor/assignment is just ignored by overload resolution (instead of being deleted in the strict sense). Since NonCopyable is not copyable and not movable, any subclass will have it's implicit (and =default) copy and move operations be defined as deleted.

Under strict iso c++, your design has the wanted semantics but unfortunately, most compilers do not strictly enforce the so called rule of five, but only enforce a subset of the implicitly deleted rule. For example, having user declared destructor for a class implies that the implicit (and =default) definitions of all copy and move operation will be deleted, but I don't know of a compiler that fails to compile or emit a warning when the implicitly declared copy constructor would be ODR used for such a class.

I came across this bug report https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58407#c16 . It suggest that compilers will probably begin to enforce or warn against the rule of five violations.