Sometimes it's necessary to prohibit a copy constructor in a C++ class so that class becomes "non-copyable". Of course, operator=
should be prohibited at the same time.
So far I've seen two ways to do that. Way 1 is to declare the method private and give it no implementation:
class Class {
//useful stuff, then
private:
Class( const Class& ); //not implemented anywhere
void operator=( const Class& ); //not implemented anywhere
};
Way 2 is to declare the method private and give it "empty" implementation:
class Class {
//useful stuff, then
private:
Class( const Class& ) {}
void operator=( const Class& ) {}
};
IMO the first one is better - even if there's some unexpected reason that leads to the copy constructor being called from the same class member function there'll be a linker error later on. In the second case this scenario will be left unnoticed until the runtime.
Are there any serious drawbacks in the first method? What's a better way if any and why?
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.
Definition. Copying of objects is achieved by the use of a copy constructor and an assignment operator. A copy constructor has as its first parameter a (possibly const or volatile) reference to its own class type. It can have more arguments, but the rest must have default values associated with them.
Copy constructor (and assignment) should be defined when ever the implicitly generated one violates any class invariant. It should be defined as deleted when it cannot be written in a way that wouldn't have undesirable or surprising behaviour.
The only disadvantage I can think of to a copy constructor is that some large objects can be expensive to copy (eg. copying a long string involves allocating a large block of memory then copying all the content).
The first one is better
Even better is C++0x 'delete' keyword:
class Class {
// useful stuff, then
public:
Class(const Class&) = delete;
void operator=(const Class&) = delete;
};
The first method is how Boost solves it (source code), as far as I know, there's no drawbacks. In fact, the linker errors are the big advantage of that method. You want the errors to be at link time, not when your client is executing your code and it suddenly crashes.
In case you are using Boost, you can save yourself some typing. This does the same as your first example:
#include <boost/utility.hpp>
class Class : boost::noncopyable {
// Stuff here
}
You can always inherit from boost::noncopyable
.
Otherwise I've never seen a reason number 2 is better than number 1 as it will allow you to "copy construct" an object within friend or class methods even though it won't actually create a true copy of the object.
As other answers suggest something else, and doesn't really attempt to answer the question, so here is my attempt:
So which approach is better? It depends on how you define prohibit copy?
If you want to prevent others (only non-friend classes and functions) from copying while allowing friends and member-functions to copy, then second approach is the way to go.
If you want to prevent everyone (friends, non-friends, member-functions) from copying, then first approach is the only correct solution.
Note that the second approach does not prevent friends and member-functions from copying (that is, from calling the copy-functions). 1
1. If you don't properly define them in the second case, then copy wouldn't work, as expected, but that is a different thing altogether. But the point is that second case doesn't prevent from calling the copy-functions. The compiler wouldn't generate any error message.
There is no drawback in your first approach, I has been using that to make "non-copyable" class ..
Personally I think you've answered your own question, and should use the first approach.
If you don't want it to be copyable at all, as you said it will throw a linker error. However if you use the second approach and you DO end up using the copy constructor by accident, it WILL compile and it WILL run; and you'll have absolutely no indication of where the inconsistency came from until you bust open a debugger. Or as sehe said, if you can use a modern compiler, use C++11's '= delete' notation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With