views:

618

answers:

1

I have several classes that I don't want to be copyable, some of these classes have pointer data members. To make these classes uncopyable I privately inherit the following class template:

template <class T>
class Uncopyable
{
  protected:
    Uncopyable() {}
    virtual ~Uncopyable() {}
  private:
    Uncopyable(const Uncopyable &);
    T & operator=(const T&);
};

Which I used like so:

class Entity : private Uncopyable<Entity> { }

This works fine, however when I compile with -Weffc++ I still get the following warning:

class Entity has pointer data members
but does not override Entity(const Entity&)
or operator=(const Entity&)

Why is it still giving me this warning?

+6  A: 

C++ says

Because a copy assignment operator is implicitly declared for a class if not declared by the user, a base class copy assignment operator is always hidden by the copy assignment operator of a derived class (13.5.3). A using-declaration (7.3.3) that brings in from a base class an assignment operator with a parameter type that could be that of a copy-assignment operator for the derived class is not considered an explicit declaration of a copy-assignment operator and does not suppress the implicit declaration of the derived class copy-assignment operator; the operator introduced by the using-declaration is hidden by the implicitly-declared copy-assignment operator in the derived class.

The bug in the code is that your base class declares the operator= to accept a reference of type of the derived class. That won't prevent an implicit public declaration of an operator= for the base. Thus, your derived class and your base class are still assignable. Try changing your noncopyable class into a non-template, which should suffice:

class Uncopyable
{
  protected:
    Uncopyable() {}
    virtual ~Uncopyable() {}
  private:
    Uncopyable(const Uncopyable &);
    Uncopyable & operator=(const Uncopyable&);
};

One more thing i have just figured in that code: Don't make the destructor of Uncopyable virtual. The reason is, no-one (apart from the derived class itself) can call delete on a pointer to Uncopyable (because 1: the destructor is protected, 2: you derive privately). So it's not the concern of Uncopyable to make the destructor of the derived class implicitly virtual. If the derived class needs to have a virtual destructor, put virtual in there instead, and leave Uncopyables' destructor non-virtual.

Johannes Schaub - litb
Thanks, I tried your suggestion but I still get the same warning, perhaps its a bug in GCC?
Kazade
oh well i just see you had -Weffc++ in effect. could very well be that it doesn't understand the noncopyable trickery. u got two choices then. either you place the copy assignment and copy ctor into the derived class (like google with their cute DISABLE_EVIL_CTORS), or you disable -Weffc++ :(
Johannes Schaub - litb
What's the version of gcc? With an apple g++ (4.0.1 build 5490) there is no such warnings with boost::noncopyable which is pretty much the same except for the virtual dtor, which the compiler actually did warn about (with -Weffc++). IMHO, the warning needs to be fixed.
obecalp
+1 for the advice on virtual. It is not only unnecessary, but in fact harmful.
Nemanja Trifunovic