To prevent copying a class, you can very easily declare a private copy constructor / assignment operators. But you can also inherit boost::noncopyable
.
I see no documentation benefit:
#include <boost/noncopyable.hpp>
struct A
: private boost::noncopyable
{
};
vs:
struct A
{
A(const A&) = delete;
A& operator=(const A&) = delete;
};
When you add move-only types, I even see the documentation as misleading. The following two examples are not copyable, though they are movable:
#include <boost/noncopyable.hpp>
struct A
: private boost::noncopyable
{
A(A&&) = default;
A& operator=(A&&) = default;
};
vs:
struct A
{
A(A&&) = default;
A& operator=(A&&) = default;
};
Under multiple inheritance, there can even be a space penalty:
#include <boost/noncopyable.hpp>
struct A
: private boost::noncopyable
{
};
struct B
: public A
{
B();
B(const B&);
B& operator=(const B&);
};
struct C
: public A
{
};
struct D
: public B,
public C,
private boost::noncopyable
{
};
#include <iostream>
int main()
{
std::cout << sizeof(D) << '\n';
}
For me this prints out:
3
But this, which I believe to have superior documentation:
struct A
{
A(const A&) = delete;
A& operator=(const A&) = delete;
};
struct B
: public A
{
B();
B(const B&);
B& operator=(const B&);
};
struct C
: public A
{
C(const C&) = delete;
C& operator=(const C&) = delete;
};
struct D
: public B,
public C
{
D(const D&) = delete;
D& operator=(const D&) = delete;
};
#include <iostream>
int main()
{
std::cout << sizeof(D) << '\n';
}
Outputs:
2
I find it much easier to declare my copy operations than to reason whether or not I'm deriving from boost::non_copyable
multiple times and if that is going to cost me. Especially if I'm not the author of the complete inheritance hierarchy.
The disavantage, according to Scott Meyers, the name is "non-natrual", if you do need to find a disavantage of it.
One concrete advantage (beyond expressing your intent slightly more clearly) is that the error will be caught sooner, at the compile stage not the link stage, if a member or friend function tries to copy an object. The base-class constructor/assignment are not accessible anywhere, giving a compile error.
It also prevents you accidentally defining the functions (i.e. typing {}
instead of ;
), a small error which may well go unnoticed, but which would then allow members and friends to make invalid copies of the object.
A small disadvantage (GCC specific) is that, if you compile your program with g++ -Weffc++
and you have classes containing pointers, e.g.
class C : boost::noncopyable
{
public:
C() : p(nullptr) {}
private:
int *p;
};
GCC doesn't understand what's happening:
warning: 'class C' has pointer data members [-Weffc++]
warning: but does not override 'C(const S&)' [-Weffc++]
warning: or 'operator=(const C&)' [-Weffc++]
While it won't complain with:
#define DISALLOW_COPY_AND_ASSIGN(Class) \
Class(const Class &) = delete; \
Class &operator=(const Class &) = delete
class C
{
public:
C() : p(nullptr) {}
DISALLOW_COPY_AND_ASSIGN(C);
private:
int *p;
};
PS I know GCC's -Weffc++ has several issues. The code that checks for "problems" is pretty simplicistic, anyway... sometimes it helps.
I can't understand why no one else seem to mention it, but:
With noncopyable
you write the name of your class just once.
Without, fivefold duplication: One A for 'class A', two to disable the assignment, and two to disable the copy constructor.
Quoting the documentation:
"The traditional way to deal with these is to declare a private copy constructor and copy assignment, and then document why this is done. But deriving from noncopyable is simpler and clearer, and doesn't require additional documentation."
http://www.boost.org/libs/utility/utility.htm#Class_noncopyable