views:

174

answers:

7

The copy assignment operator has the usual signature:

    my_class & operator = (my_class const & rhs);

Does the following signature have any practical use?

    my_class const & operator = (my_class const & rhs);

You can only define one or the other, but not both.

A: 

Yes, it should be const. Otherwise clients can do this:

class MyClass
{
public:
      MyClass & operator = (MyClass const & rhs);
}

void Foo() {
    MyClass a, b, c;
    (a = b) = c; //Yikes!
}
Billy ONeal
I'm confused...that's normal.
GMan
"No it shouldn't be const, because it breaks the following code: ... (a = b) = c; // Yikes!". :)
Johannes Schaub - litb
But then you are violating the convention set by all the built-in types and types like `vector`, `string`, etc. Unless you have a real reason, just "do what the ints do". I think Scott Meyers coined that phrase.
Brian Neal
Johannes Schaub - litb
@Johannes Schaub - litb, @GMan:, @Brian Neal: The parenthesis around `(a = b)` are what make it wrong. Remove the ()s and it's perfectly okay.
Billy ONeal
Why return a `MyClass`-anything? Why not just return `void` if you don't want the result to be used?
Potatoswatter
@Billy: What should be wrong with the parenthesis case? Going with your `int` argumentation, `(i1=i2)=i3` is perfectly fine.
Georg Fritzsche
Writing `(a = b) = c` means one of two things - either `operator=` has an unusual post-condition, meaning that the code has a different result from `a = c`, or else the first assignment is redundant. Assuming a "normal" operator=, I don't see any reason to support it. I also don't see any reason to go out of my way to prevent it. There are cases where const-safety makes it harder to write bad code, but I don't believe this is one of them. So I think this is a non-reason.
Steve Jessop
@gf: Just because something compiles does not mean it's what clients want. In 99% of all cases, that is a typo.
Billy ONeal
Actually i somehow misread *Brian Neal* for *Billy ONeal* above, thus the `int` argumentation reference... *sigh* ... As for the typos... there are too many features in C++ that can be used erroneously - disallowing other valid uses just to take care of possible typos doesn't help either.
Georg Fritzsche
@Potatoswatter - if you have `operator=` return void, you can't do such common idioms as `a = b = c` or `if ((a = foo()) == value)`. Having `operator=` return itself allows for much common shorthand.
R Samuel Klatchko
A: 

As in any other usage of const, const is the default, unless you really want to let the user change.

Pavel Radzivilovsky
In this case, you have no control over the user changing the object, because they already have a non-const version sitting around.
Dennis Zickefoose
+1  A: 

Effective C++ explains that this would break compatibility with the built-in types of C++.

You can do this with plain ints:

(x = y) = z;

so he reasons, however silly this looks like, one should be able to do the same with one's own type as well.

This example is there in 2nd Edition, although not anymore in the 3rd. However, this quote from 3rd Ed., Item 10 tells the same still:

[...] assignment returns a reference to its left-hand argument, and that's the convention you should follow when you implement assignment operators for your classes:

class Widget {
public:
  ...
  Widget& operator=(const Widget& rhs)   // return type is a reference to
  {                                      // the current class
  ...
  return *this;                        // return the left-hand object
  }
  ...
};
Péter Török
Hmm.... I think it was that you should **always** declare `operator*` with a const reference to *avoid* `(a * b) = c`, which is illegal with the built in types.
Billy ONeal
@BillyONeal - with `operator*` you should be returning an object, not a reference.
R Samuel Klatchko
+4  A: 

Don't do that. It prevent a client from writing something like:

(a = b).non_const_method();

instead of the longer form:

a = b;
a.non_const_method();

While you may not like the shorthand style, it's really up to the user of the library to decide how they want to write the code.

R Samuel Klatchko
Actually - it should also be up to the library to prevent users from doing something the library isn't prepared to handle.
Michael Burr
@MichaelBurr - agreed, but that is not the issue here. The above is just short hand notation for `a = b; a.non_const_method();`
R Samuel Klatchko
Michael Burr
let's be particular: `a=b=c;` wouldn't work. and that's a very common thing to do.
wilhelmtell
@MichaelBurr - I don't see how it could ever be dangerous. In order to do `a = b;` `a` must be non-const so in the next line you can modify it any way you choose. Having `operator=` return a non-const just allows you to combine that in a single line.
R Samuel Klatchko
@willhelmtell - `operator=` returning const will still allow `a = b = c;` but will prevent `(a = b) = c;`
R Samuel Klatchko
A: 

An answer that mirrors one from http://stackoverflow.com/questions/2447696/overloading-assignment-operator-in-c/2448144#2448144:

Returning a const& will still allow assignment chaining:

a = b = c;

But will disallow some of the more unusual uses:

(a = b) = c;

Note that this makes the assignment operator have semantics similar to what it has in C, where the value returned by the = operator is not an lvalue. In C++, the standard changed it so the = operator returns the type of the left operand, so the result is an lvalue. But as Steve Jessop noted in a comment to another answer, while that makes it so the compiler will accept

(a = b) = c;

even for built-ins, the result is undefined behavior for built-ins since a is modified twice with no intervening sequence point. That problem is avoided for non-builtins with an operator=() because the operator=() function call serves as a sequence point.

I see no problem returning a const& unless you want to specifically allow the lvalue semantics (and design the class to ensure it acts sensibly with those semantics). If you're users want to do something unusual with the result of operator=(), I'd prefer that the class disallow it rather than hope it gets it right by chance instead of design.

Also. note that while you said:

You can only define one or the other, but not both.

that's because the function signature in C++ doesn't take into account the return value type. You could however have multiple operator=() assignement operatiors that take different parameters and return different types appropriate to the parameter types:

my_class& operator=( my_class& rhs);
my_class const& operator=(my_class const& rhs);

I'm not entirely sure what this would buy you though. The object being assigned to (that is presumably the reference being returned) is non-const in both cases, so there's no logical reason to return a const& just because the righ-hand-side of the = is const. But maybe I'm missing something...

Michael Burr
A: 

Why is everyone obsessing over (a = b) = c? Has that ever been written by accident?

There is probably some unforeseen utility of the result of assignment being altered. You don't just make arbitrary rules against made-up examples that look funny. Semantically there is no reason that it should be const, so do not declare it const for lexical side effects.

Here is an example of somewhat reasonable code that breaks for const & assignment:

my_class &ref = a = b;
Potatoswatter
+3  A: 

The principle reason to make the return type of copy-assignment a non-const reference is that it is a requirement for "Assignable" in the standard.

If you make the return type a const reference then your class won't meet the requirements for use in any of the standard library containers.

Charles Bailey
+1, end of discussion :-)
Steve Jessop
None of the answers answered my question directly. 'Has anyone found the need to declare the return parameter of a copy assignment operator const?'All the answers indirectly said 'No, I have not found a need... ' and the reason is because it violates the rule stated in this answer.My question arose from a conversation I had with someone who said they did return const. They were trying to prevent copying of the object. Not having the details, I believed the overall design was bad. Thought I would ask to see if there was a legitimate reason to return const. Thanks for all the answers!
Keith M Smith
@Keith: OK, my answer is also 'no'.
Charles Bailey