问题
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?
回答1:
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.
回答2:
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.
回答3:
Summarizing what others have said:
Advantages of boost::noncopyable
over private copy methods:
- It is more explicit and descriptive in the intent. Using private copy functions is an idiom that takes longer to spot than
noncopyable
. - It is less code / less typing / less clutter / less room for error (the easiest would be accidentally providing an implementation).
- 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.
- 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.
- (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
:
- No boost dependency
回答4:
- The intent of boost::noncopyable is clearer.
- Boost::noncopyable prevents the classes methods from accidentally using the private copy constructor.
- Less code with boost::noncopyable.
回答5:
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.
回答6:
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
回答7:
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.
回答8:
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.
回答9:
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.
回答10:
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:
The disavantage, according to Scott Meyers, the name is "non-natrual", if you do need to find a disavantage of it.
来源:https://stackoverflow.com/questions/7823990/what-are-the-advantages-of-boostnoncopyable