Skip to content

Boost Noncopyable Assignment Of Benefits

In some cases, an instance of a C++ class should not be copied at all. There are three ways to prevent such an object copy: keeping the copy constructor and assignment operator private, using a special non-copyable mixin, or deleting those special member functions.

A class that represents a wrapper stream of a file should not have its instance copied around. It will cause a confusion in the handling of the actual I/O system. In a similar spirit, if an instance holds a unique private object, copying the pointer does not make sense. A somehow related problem but not necessarily similar is the issue of object slicing.

The following illustration demonstrates a simple class that is supposed to have a unique owner, an instance of .

For this purpose, the implementation of is as simple as:

To show the issue, a helper function is implement as follows:

From this example, it is obvious that an instance of must not be copied. In particular, another clone of a similar car should not automatically belong to the same owner. In fact, running the subsequent code:

will give the output:

Owner is Joe Sixpack Owner is Joe Sixpack

How can we prevent this accidental object copy?

Method 1: Private copy constructor and copy assignment operator

A very common technique is to declare both the copy constructor and copy assignment operator to be private. We do not even need to implement them. The idea is so that any attempt to perform a copy or an assignment will provoke a compile error.

In the above example, will be modified to look like the following. Take a look closely at two additional private members of the class.

Now if we try again to assign an instance of to a new one, the compiler will complain loudly:

example.cpp:35:22: error: calling a private constructor of class 'Car' Car anotherSedan = sedan; ^ example.cpp:22:3: note: declared private here Car(const Car&); ^ 1 error generated.

If writing two additional lines containing repetitive names is too cumbersome, a macro could be utilized instead. This is the approach used by WebKit, see its macro from wtf/Noncopyable.h (do not be alarmed, in the context of WebKit source code, WTF here stands for Web Template Framework). Chromium code, as shown in the file base/macros.h, distinguishes between copy constructor and assignment, denoted as and macros, respectively.

Method 2: Non-copyable mixin

The idea above can be extended to create a dedicated class which has the sole purpose to prevent object copying. It is often called as Noncopyable and typically used as a mixin. In our example, the class can then be derived from this .

Boost users may be already familiar with boost::noncopyable, the Boost flavor of the said mixin. A conceptual, self-contained implementation of that mixin will resemble something like the following:

Our lovely Car class can be written as:

Compared to the first method, using has the benefit of making the intention very clear. A quick glance at the class, right on its first line, and you know right away that its instance is not supposed to be copied.

Method 3: Deleted copy constructor and copy assignment operator

For modern applications, there is less and less reason to get stuck with the above workaround. Thanks to C++11, the solution becomes magically simple: just delete the copy constructor and assignment operator. Our class will look like this instead:

Note that if you use mixin with a compiler supporting C++11, the implementation of also automatically deletes the said member functions.

With this approach, any accidental copy will result in a quite friendlier error message:

example.cpp:34:7: error: call to deleted constructor of 'Car' Car anotherSedan = sedan; ^ ~~~~~ example.cpp:10:3: note: 'Car' has been explicitly marked deleted here Car(const Car&) = delete; ^

So, which of the above three methods is your favorite?

The latest version of this topic can be found at Explicitly Defaulted and Deleted Functions.

In C++11, defaulted and deleted functions give you explicit control over whether the special member functions are automatically generated. Deleted functions also give you simple language to prevent problematic type promotions from occurring in arguments to functions of all types—special member functions, as well as normal member functions and non-member functions—which would otherwise cause an unwanted function call.

In C++, the compiler automatically generates the default constructor, copy constructor, copy-assignment operator, and destructor for a type if it does not declare its own. These functions are known as the special member functions, and they are what make simple user-defined types in C++ behave like structures do in C. That is, you can create, copy, and destroy them without any additional coding effort. C++11 brings move semantics to the language and adds the move constructor and move-assignment operator to the list of special member functions that the compiler can automatically generate.

This is convenient for simple types, but complex types often define one or more of the special member functions themselves, and this can prevent other special member functions from being automatically generated. In practice:

  • If any constructor is explicitly declared, then no default constructor is automatically generated.

  • If a virtual destructor is explicitly declared, then no default destructor is automatically generated.

  • If a move constructor or move-assignment operator is explicitly declared, then:

    • No copy constructor is automatically generated.

    • No copy-assignment operator is automatically generated.

  • If a copy constructor, copy-assignment operator, move constructor, move-assignment operator, or destructor is explicitly declared, then:

    • No move constructor is automatically generated.

    • No move-assignment operator is automatically generated.

Additionally, the C++11 standard specifies the following additional rules:

  • If a copy constructor or destructor is explicitly declared, then automatic generation of the copy-assignment operator is deprecated.
  • If a copy-assignment operator or destructor is explicitly declared, then automatic generation of the copy constructor is deprecated.

In both cases, Visual Studio continues to automatically generate the necessary functions implicitly, and does not emit a warning.

The consequences of these rules can also leak into object hierarchies. For example, if for any reason a base class fails to have a default constructor that's callable from a deriving class—that is, a or constructor that takes no parameters—then a class that derives from it cannot automatically generate its own default constructor.

These rules can complicate the implementation of what should be straight-forward, user-defined types and common C++ idioms—for example, making a user-defined type non-copyable by declaring the copy constructor and copy-assignment operator privately and not defining them.

Before C++11, this code snippet was the idiomatic form of non-copyable types. However, it has several problems:

  • The copy constructor has to be declared privately to hide it, but because it’s declared at all, automatic generation of the default constructor is prevented. You have to explicitly define the default constructor if you want one, even if it does nothing.

  • Even if the explicitly-defined default constructor does nothing, it's considered non-trivial by the compiler. It's less efficient than an automatically generated default constructor and prevents from being a true POD type.

  • Even though the copy constructor and copy-assignment operator are hidden from outside code, the member functions and friends of can still see and call them. If they are declared but not defined, calling them causes a linker error.

  • Although this is a commonly accepted idiom, the intent is not clear unless you understand all of the rules for automatic generation of the special member functions.

In C++11, the non-copyable idiom can be implemented in a way that is more straightforward.

Notice how the problems with the pre-C++11 idiom are resolved:

  • Generation of the default constructor is still prevented by declaring the copy constructor, but you can bring it back by explicitly defaulting it.

  • Explicitly defaulted special member functions are still considered trivial, so there is no performance penalty, and is not prevented from being a true POD type.

  • The copy constructor and copy-assignment operator are public but deleted. It is a compile-time error to define or call a deleted function.

  • The intent is clear to anyone who understands and . You don't have to understand the rules for automatic generation of special member functions.

Similar idioms exist for making user-defined types that are non-movable, that can only be dynamically allocated, or that cannot be dynamically allocated. Each of these idioms have pre-C++11 implementations that suffer similar problems, and that are similarly resolved in C++11 by implementing them in terms of defaulted and deleted special member functions.

You can default any of the special member functions—to explicitly state that the special member function uses the default implementation, to define the special member function with a non-public access qualifier, or to reinstate a special member function whose automatic generation was prevented by other circumstances.

You default a special member function by declaring it as in this example:

Notice that you can default a special member function outside the body of a class as long as it’s inlinable.

Because of the performance benefits of trivial special member functions, we recommend that you prefer automatically generated special member functions over empty function bodies when you want the default behavior. You can do this either by explicitly defaulting the special member function, or by not declaring it (and also not declaring other special member functions that would prevent it from being automatically generated.)

Visual Studio does not support defaulted move constructors or move-assignment operators as the C++11 standard mandates. For more information, see the Defaulted and Deleted functions section of Support For C++11/14/17 Features (Modern C++).

You can delete special member functions as well as normal member functions and non-member functions to prevent them from being defined or called. Deleting of special member functions provides a cleaner way of preventing the compiler from generating special member functions that you don’t want. The function must be deleted as it is declared; it cannot be deleted afterwards in the way that a function can be declared and then later defaulted.

Deleting of normal member function or non-member functions prevents problematic type promotions from causing an unintended function to be called. This works because deleted functions still participate in overload resolution and provide a better match than the function that could be called after the types are promoted. The function call resolves to the more-specific—but deleted—function and causes a compiler error.

Notice in the preceding sample that calling by using a argument would cause a compiler error, but calling by using an argument would not; in the case, the argument will be promoted from to and successfully call the version of the function, even though that might not be what’s intended. To ensure that any call to this function by using a non-double argument causes a compiler error, you can declare a template version of the function that’s deleted.

struct noncopyable { noncopyable() {}; private: noncopyable(const noncopyable&); noncopyable& operator=(const noncopyable&); };
struct noncopyable { noncopyable() =default; noncopyable(const noncopyable&) =delete; noncopyable& operator=(const noncopyable&) =delete; };
struct widget { widget()=default; inline widget& operator=(const widget&); }; inline widget& widget::operator=(const widget&) =default;
struct widget { // deleted operator new prevents widget from being dynamically allocated. void* operator new(std::size_t) = delete; };
// deleted overload prevents call through type promotion of float to double from succeeding. void call_with_true_double_only(float) =delete; void call_with_true_double_only(double param) { return; }
template < typename T > void call_with_true_double_only(T) =delete; //prevent call through type promotion of any T to double from succeeding. void call_with_true_double_only(double param) { return; } // also define for const double, double&, etc. as needed.