What are the advantages of boost::noncopyable

45.6k views Asked by At

To prevent copying a class, you can very easily declare a private copy constructor / assignment operators. But you can also inherit boost::noncopyable.

What are the advantages / disadvantages of using boost in this case?

11

There are 11 answers

1
tenfour On BEST ANSWER

Summarizing what others have said:

Advantages of boost::noncopyable over private copy methods:

  1. It is more explicit and descriptive in the intent. Using private copy functions is an idiom that takes longer to spot than noncopyable.
  2. It is less code / less typing / less clutter / less room for error (the easiest would be accidentally providing an implementation).
  3. It embeds meaning right in the type's metadata, similar to a C# attribute. You can now write a function which accepts only objects which are noncopyable.
  4. It potentially catches errors earlier in the build process. The error will be presented at compile-time rather than link-time, in the case that the class itself or friends of the class are doing the erroneous copying.
  5. (almost the same as #4) Prevents the class itself or friends of the class from calling the private copy methods.

Advantages of private copy methods over boost::noncopyable:

  1. No boost dependency
8
Sarfaraz Nawaz On

It makes the intent explicit and clear, otherwise one has to see the definition of the class,and search for the declaration related to copy-semantic, and then look for the access-specifier in which it is declared, in order to determine whether the class is noncopyable or not. Other way to discover it by writing code that requires copy-semantic enabled and see the compilation error.

0
Nikko On

The advantage is that you don't have to write a private copy constructor and a private copy operator yourself and it expresses clearly your intention without writing additional documentation.

0
thiton On
  1. The intent of boost::noncopyable is clearer.
  2. Boost::noncopyable prevents the classes methods from accidentally using the private copy constructor.
  3. Less code with boost::noncopyable.
0
Viktor Sehr On

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

6
Mike Seymour On

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.

0
H Xu On

The disavantage, according to Scott Meyers, the name is "non-natrual", if you do need to find a disavantage of it.

2
wjl On

I'd rather use boost::noncopyable than manually delete or privatize the copy constructor and assignment operator.

However, I almost never use either method, because:

If I am making a non-copyable object, there has to be a reason it is non-copyable. This reason, 99% of the time, is because I have members that can't be copied meaningfully. Chances are, such members would also be better suited as private implementation details. So I make most such classes like this:

struct Whatever {
  Whatever();
  ~Whatever();
  private:
  struct Detail;
  std::unique_ptr<Detail> detail;
};

So now, I have a private implementation struct, and since I've used std::unique_ptr, my top-level class is non-copyable for free. The link errors that come from this are understandable because they talk about how you can't copy a std::unique_ptr. To me, this is all the benefits of boost::noncopyable and a private implementation rolled into one.

The benefit with this pattern is later, if I decide that I did indeed want to make my objects of this class copyable, I can just add and implement a copy constructor and/or assignment operator without changing the class hierarchy.

11
Howard Hinnant On

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.

1
ansgri On

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.

0
manlio On

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.