Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Value parameters to operator= cause strange compilation error

Tags:

c++

I'm trying to relearn C++, and I tend to want to have an intricate understanding of how everything works (not just "how do I do this"). So I'm wondering why this produces the error it does. Yes, I know that an overloaded assignment operator is supposed to use references (and it works fine if I do), but I'm hoping that an answer to this question might help me learn more about the language rules.

class some_class {
public:
    int n1;
    some_class(int z) : n1(z) { }
    some_class(some_class &x) : n1(x.n1) { }
    some_class operator= (some_class x) { n1 = x.n1; return *this; }
//  some_class & operator= (some_class & x) { n1 = x.n1; return *this; } works fine
};

main () {
    some_class a(10);
    some_class b(20);
    some_class c(30);
    c = b = a;          // error here
}

The compiler (C++03) gives me this, on the c = b = a line:

In function 'int main()':
   error: no matching function for call to 'some_class::some_class(some_class)'
   note: candidates are: some_class::some_class(some_class&)
   note:                 some_class::some_class(int)
   error:   initializing argument 1 of 'some_class some_class::operator=(some_class)'

It's confusing to me, because b = a works fine, and it's looking for a constructor that I'm not legally allowed to declare. I realize that in c = b = a, the b = a part returns a value (not a reference), and that may result in the result being copied to a temporary. But why would c = <temporary> result in a compilation error when b = a wouldn't? Any idea what's going on?

like image 628
ajb Avatar asked Jun 06 '26 13:06

ajb


1 Answers

Your copy constructor has a non-const reference as its parameter. Temporaries can't be bound to non-const references. When you do:

c = b = a;

This is equivalent (as you say) to:

c.operator=(<temporary>);

It therefore tries to invoke your copy constructor with a temporary whilst initialising the first argument of the call to operator=. This fails for the reason mentioned. A sensible way to fix it is to change the signature of operator= to the more conventional:

some_class& operator=(const some_class& x);

The copy constructor would not then be needed in the implementation of operator=, since the argument to operator= would not be copied. However, copy constructors should generally take a const reference parameter, so you should also change the signature of the copy constructor to:

some_class(const some_class& x);
like image 118
Stuart Golodetz Avatar answered Jun 08 '26 03:06

Stuart Golodetz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!