What are the advantages of boost::noncopyable
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
What are use cases for booster::noncopyable?
I find it useful whenever you have a class that has a pointer as a member variable which that class owns (ie is responsible for destroying). Unless you're using shared_ptr<>
or some other reference-counted smart pointer, you can't safely copy or assign the class, because in the destructor you will want to delete
the pointer. However, you don't know if a copy of the class has been taken and hence you'll get either a double-delete or access violation from dereferencing a freed pointer.
If you inherit from noncopyable
then it has two benefits:
- It prevents the class from being copied or assigned
- It makes the intention clear from looking at the class definition, ie self-documenting code
eg
class MyClass : boost::noncopyable
{
...
};
Can a non-copyable member be used as alternative to make an object non-copyable?
Since C++11, the proper idiom for making a class non-copyable is to = delete
the copy constructor/assignment operator. That's what C++ programmers are told to do, and that's what other C++ programmers will expect to see when looking for that behavior in your class..
It's fine to have a subobject (member or base class) that is non-copyable, and thus your default copy constructor/assignment operator will be implicitly deleted. But you should only do this for a subobject that happens to be non-copyable. That is, you have a unique_ptr<T>
or mutex
or whatever as a member because you need a unique_ptr<T>
or a mutex
as class instance data. Not because you're using it as a hack to make the type non-copyable.
The downsides of using a member subobject for this purpose are:
It muddles the meaning of your code. Your
mutex _dummy;
example tells me that your type has amutex
in it. If nothing ever uses that variable, then that tells me that your code is rather incoherent; if you don't need a subobject, you don't declare one.= delete
is the proper idiom, so it is what you should use.boost::noncopyable
was the C++98/03 idiom because it was an empty class. And thus, common empty base optimization would ensure that it wouldn't take up any space in the derived class. Empty members get no such optimization, so a memberboost::noncopyable
will always make your class bigger, to no advantage. And while you could point to the upcoming C++20[[no_unique_address]]
attribute, see reason #1.
With explicitly deleted member functions in C++11, is it still worthwhile to inherit from a noncopyable base class?
Well, this:
private:
MyClass(const MyClass&) {}
MyClass& operator=(const MyClass&) {}
Still technically allows MyClass
to be copied by members and friends. Sure, those types and functions are theoretically under your control, but the class is still copyable. At least with boost::noncopyable
and = delete
, nobody can copy the class.
I don't get why some people claim it's easier to make a class non-copyable in C++11.
It's not so much "easier" as "more easily digestible".
Consider this:
class MyClass
{
private:
MyClass(const MyClass&) {}
MyClass& operator=(const MyClass&) {}
};
If you are a C++ programmer who has read an introductory text on C++, but has little exposure to idiomatic C++ (ie: a lot of C++ programmers), this is... confusing. It declares copy constructors and copy assignment operators, but they're empty. So why declare them at all? Yes, they're private
, but that only raises more questions: why make them private?
To understand why this prevents copying, you have to realize that by declaring them private, you make it so that non-members/friends cannot copy it. This is not immediately obvious to the novice. Nor is the error message that they will get when they try to copy it.
Now, compare it to the C++11 version:
class MyClass
{
public:
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
};
What does it take to understand that this class cannot be copied? Nothing more than understanding what the = delete
syntax means. Any book explaining the syntax rules of C++11 will tell you exactly what that does. The effect of this code is obvious to the inexperienced C++ user.
What's great about this idiom is that it becomes an idiom because it is the clearest, most obvious way to say exactly what you mean.
Even boost::noncopyable
requires a bit more thought. Yes, it's called "noncopyable", so it is self-documenting. But if you've never seen it before, it raises questions. Why are you deriving from something that can't be copied? Why do my error messages talk about boost::noncopyable
's copy constructor? Etc. Again, understanding the idiom requires more mental effort.
Noncopyable and Nonmovable together?
While a "noncopyable" will work, an "nonmovable" base class will not provide what you expect:
#include <utility>
#include <iostream>
struct nonmovable
{
nonmovable() = default;
nonmovable(const nonmovable&) { std::cout << "copy\n"; }
nonmovable& operator = (const nonmovable&) { std::cout << "asign\n"; return *this; }
nonmovable(nonmovable&&) = delete;
nonmovable& operator = (nonmovable&&) = delete;
};
struct X : nonmovable {};
int main()
{
nonmovable n0;
nonmovable n1(n0);
// error: use of deleted function ‘nonmovable::nonmovable(nonmovable&&)’:
//nonmovable n2(std::move(n0));
X x0;
X x1(x0);
// However, X has a copy constructor not applying a move.
X x2(std::move(x0));
}
In addition, move construction and move assignment must be enabled explicitly after deletion of the copy constructor, if desiered:
struct noncopyable
{
noncopyable() = default;
// Deletion of copy constructor and copy assignment makes the class
// non-movable, too.
noncopyable(const noncopyable&) = delete;
noncopyable& operator = (const noncopyable&) = delete;
// Move construction and move assignment must be enabled explicitly, if desiered.
noncopyable(noncopyable&&) = default;
noncopyable& operator = (noncopyable&&) = default;
};
The, names "noncopyable" and "nonmovable" itself are good descriptive names. However, "boost::noncopyable" is both (non copyable and non movable), which might be a better (historical) design decision.
C++ how noncopyable works?
Default copy constructor and assignment operator are generated by the compiler in the derived class and not added by the programmer
The implicit functions will try to call their counterparts in the base class. This won't be possible since those are private to the base class, so you'll get a compilation error. This is how the base class is intended to work.
Copy constructor and assignment operator are defined and declared public in the derived class by the programmer
Then you've defeated the purpose of inheriting from the base class; your derived class is now copyable via these functions.
Copy constructor and assignment operator are defined and declared private in the derived class by the programmer
Again, you've defeated the base class and made your class copyable; but only within its member and friend functions.
Is it good practice to generally make heavyweight classes non-copyable?
Restricting your users isn't always a good idea. Just documenting that copying may be expensive is enough. If a user really wants to copy, then using the native syntax of C++ by providing a copy constructor is a much cleaner approach.
Therefore, I think the real answer depends on the context. Perhaps the real class you're writing (not the imaginary Shape) shouldn't be copied, perhaps it should. But as a general approach, I certainly can't say that one should discourage users from copying large objects by forcing them to use explicit method calls.
Related Topics
How to Remove Constness of Const_Iterator
Why/When Is _Declspec( Dllimport ) Not Needed
Stdafx + Header File - Order of Inclusion in Mfc Application
Can C++ Code Be Valid in Both C++03 and C++11 But Do Different Things
C++ Header Files, Code Separation
Search for a Struct Item in a Vector by Member Data
Call to Pure Virtual Function from Base Class Constructor
C++ Return Value Without Return Statement
How to Programmatically Gain Root Privileges
How to Define a Template Function Within a Template Class Outside of the Class Definition
How to Leverage Qt to Make a Qobject Method Thread-Safe
Understanding Boost.Spirit's String Parser
Why Did Microsoft Abandon Long Double Data Type
Linking Libstdc++ Statically: Any Gotchas
Static Variables in an Inlined Function
How to Define a C++ Preprocessor MACro Through the Command Line with Cmake