More C++ Idioms/Non-copyable Mixin
Non-copyable Mixin
edit
Intent
editTo prevent objects of a class from being copy-constructed or assigned to each other.
Also Known As
editMotivation
editMany times it makes sense to prevent copying of objects of a class. For example, a class that encapsulates network connections. Copying can't be meaningfully defined for such classes. So it should be explicitly prevented without relying on guidelines or discipline on the programmer's part. The intent should also be easily identifiable just by looking at the declaration of a class to improve readability.
Solution and Sample Code
editA class called non-copyable is defined which has a private copy constructor and copy assignment operator.
class NonCopyable
{
public:
NonCopyable (const NonCopyable &) = delete;
NonCopyable & operator = (const NonCopyable &) = delete;
protected:
NonCopyable () = default;
~NonCopyable () = default; /// Protected non-virtual destructor
};
class CantCopy : private NonCopyable
{};
CantCopy objects can't be copied because the copy constructor and copy assignment operators of the private base class NonCopyable are not accessible to the derived class. 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. private members of NonCopyable need not be defined. NonCopyable can also be categorized as a mixin-from-above because it defines a reusable module that "mixes-in" the feature of "non-copyability" into the derived class from "above". A CRTP based solution is given below. (This allows for Empty Base Optimization with multiple inheritance [see the Discussion page].)
template <class T>
class NonCopyable
{
public:
NonCopyable (const NonCopyable &) = delete;
T & operator = (const T &) = delete;
protected:
NonCopyable () = default;
~NonCopyable () = default; /// Protected non-virtual destructor
};
class CantCopy : private NonCopyable <CantCopy>
{};
Explicit copy-constructor
It is worthwhile to note that C++ allows one more way to control copy-construction. An explicit copy-constructor will prevent the compiler from calling a copy-constructor implicitly. I.e., passing an object by value and returning an object by value will be disabled for the class having an explicit copy-constructor. However, making explicit copies is allowed. On gcc, use -fno-elide-constructors option to disable copy-elision. This option is useful to observe (actually not observe!) the effects of Return Value Optimization. It is generally not recommended to disable this important optimization.
struct NoImplicitCopy
{
NoImplicitCopy () = default;
explicit NoImplicitCopy (const NoImplicitCopy &) = default;
};
NoImplicitCopy foo() // Compiler error because copy-constructor must be invoked implicitly to return by value.
{
NoImplicitCopy n;
return n;
}
void bar(NoImplicitCopy n) // Compiler error because copy-constructor must be invoked implicitly to pass by value.
{
}
int main(void)
{
NoImplicitCopy n;
NoImplicitCopy x(n); // This is fine. explicit copy.
n = foo();
bar(n);
}
Known Uses
editRelated Idioms
editCuriously Recurring Template Pattern
References
edit- ISO/IEC 14882:2003 C++ Standard §12.8/4, §12.8/7