RobertL
RobertL

Reputation: 4266

Macros to disallow class copy and assignment. Google -vs- Qt

To disallow copying or assigning a class it's common practice to make the copy constructor and assignment operator private. Both Google and Qt have macros to make this easy and visible. These macros are:

Google:

#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
  TypeName(const TypeName&);   \
  void operator=(const TypeName&) 

Qt:

#define Q_DISABLE_COPY(Class) \
  Class(const Class &); \     
  Class &operator=(const Class &);

Questions: Why are the signatures of the two assignment operators different? It seems like the Qt version is correct. What is the practical difference between the two?

Upvotes: 37

Views: 19643

Answers (11)

sandwood
sandwood

Reputation: 2167

In practice I would say that both should not be used anymore if you have a C++11 compiler.

You should instead use the delete feature , see here

Meaning of = delete after function declaration

and here

http://www.stroustrup.com/C++11FAQ.html#default

Why : essentially because compiler message is much more clearer. When the compiler need one of the copy or copy assignment operator, it immediately points out to the line where the =delete was coded.

Better and complete explanations can also be found in Item 11: Prefer deleted functions to private undefined ones from Effective Modern C++ book by Scott Meyers

Upvotes: 0

Michael Burr
Michael Burr

Reputation: 340316

As several other answers have mentioned, the return type of the function doesn't participate in the function signature, so both declarations are equivalent as far as making the assignment operator unusable by clients of the class.

Personally I prefer the idiom of having a class privately inherit from an empty non-copyable base class (like boost::noncopyable, but I have my own so I can use it in projects that don't have boost available). The empty base class optimization takes care of making sure there's zero overhead, and it's simple, readable, and doesn't rely on the dreaded preprocessor macro functionality.

It also has the advantage that copy and assignment can't even be used within class implementation code - it'll fail at compile time while these macros will fail at link time (likely with a less informative error message).

Upvotes: 1

sellibitze
sellibitze

Reputation: 28107

See Boost.Utility, specifically boost::noncopyable. It's not a macro but a base class with private copy and assignment. It prevents the compiler from generating implicit copy and assignment in derived classes.

edit: Sorry, this was not an answer to the original question. By the way, boost::noncopyable uses a const reference as return type for the assignment operator. I was under the impression that the type of the return value doesn't matter since it's not supposed to be used. Still, making the operator private doesn't prevent usage inside the class or friends in which case a non-usual return type (like void, a const reference, etc) might lead to compilation errors and catch additional bugs.

Upvotes: 10

David Thornley
David Thornley

Reputation: 57056

From the standard, 12.8, clause 9: "A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X&, or const volatile X&." It says nothing about the return type, so any return type is permissible.

Clause 10 says "If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly."

Therefore, declaring any X::operator=(const X&) (or any other of the specified assignment types) is sufficient. Neither the body nor the return type is significant if the operator will never be used.

Therefore, it's a stylistic difference, with one macro doing what we'd likely expect and one saving a few characters and doing the job in a way that's likely to surprise some people. I think the Qt macro is better stylistically. Since we're talking macro, we're not talking about the programmer having to type anything extra, and failing to surprise people is a good thing in a language construct.

Upvotes: 4

MattyT
MattyT

Reputation: 6651

Incidentally, if you have access to the Boost libraries (You don't? Why the heck not??), The Utility library has had the noncopyable class for a long time:

class YourNonCopyableClass : boost::noncopyable {

Clearer IMHO.

Upvotes: 0

bartsimpson
bartsimpson

Reputation: 213

I'd just like to mention that there is an alternative strategy for implementing an abstraction for disallowing copy and assignment of a class. The idea is to use inheritance instead of the preprocessor. I personally prefer this approach as I follow the rule of thumb that it is best to avoid using the preprocessor when at all possible.

boost::noncopyable is an example implementation. It is used as follows:

class A : noncopyable
{
    ...
};

Upvotes: 16

P Shved
P Shved

Reputation: 99354

Qt version is backward compatible, while google's is not.

If you develop your library and deprecate the use of assignment before you completely remove it, in Qt it will most likely retain the signature it originally had. In this case older application will continue to run with new version of library (however, they won't compile with the newer version).

Google's macro doesn't have such a property.

Upvotes: 1

Frerich Raabe
Frerich Raabe

Reputation: 94409

Others have already answered why it's legal to have different return values for operator=; IMHO jalf said it best.

However, you might wonder why Google uses a different return type, and I suspect it's this:

You don't have to repeat the type name when disabling the assignment operator like this. Usually the type name is the longest part of the declaration.

Of course, this reason is void given that a macro is used but still - old habits die hard. :-)

Upvotes: 2

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 248129

It doesn't matter. The return type is not part of a function's signature, as it does not participate in overload resolution. So when you attempt to perform an assignment, both declarations will match, regardless of whether you use the return type.

And since the entire point in these macros is that the functions will never get called, it doesn't matter that one returns void.

Upvotes: 50

aJ.
aJ.

Reputation: 35460

Both serve the same purpose

Once you write this one:

Class &operator=(const Class &);

you will get the benefits of chain assignments. But in this case you want the assignment operator to be private. so it doesn't matter.

Upvotes: 1

sharptooth
sharptooth

Reputation: 170509

There's no practical difference. The assignment operator signatures differ just as a matter of style. It's usual to have an assignment operator returning a reference to allow chaining:

a = b = c;

but a version returning void is also legal and will work just fine for cases when the only purpose is to just declare the operator private and therefore prohibited to use.

Upvotes: 5

Related Questions