1
class Complex{
    int x,y;
    
    public:
    
    void setdata(int x,int y)
    {
        this->x=x;this->y=y;
    }
    Complex add(Complex &c)
    {
        Complex temp;
        temp.x=this->x + c.x;
        temp.y=this->y + c.y;
        return temp; 
    }
    Complex(Complex &c) // copy constructor
    {
        x=c.x; y=c.y;
    }
    Complex() // Simple default constructor
    {

    }
    void showdata()
    {cout<< this->x <<" "<< this->y;}
};

int main()
{
    Complex c1; c1.setdata(3,4);
    Complex c2=c1; 
    Complex c3 = c1.add(c2);
    //c3.showdata();
    cout<<"\n"<<Complex::v;
    return 0;
}

Complex c2=c1; This is fine with compiler. while Complex c3 = c1.add(c2); creates errors namely:

  • class Complex has no suitable copy constructor.
  • cannot bind non-const lvalue reference of type Complex & to an rvalue of type Complex.

Is this related to memory being released after the temp variable is destroyed or something else as i am not able to understand the errors prescribed by Compiler as mentioned above?

user3840170
  • 26,597
  • 4
  • 30
  • 62
  • 2
    `Complex(Complex &c)` -> `Complex(Complex const& c)` – Mike Vine Jan 14 '22 at 12:37
  • you should make things `const` by default. This will make the error go away, but to explain the issue a bit more is needed i guess – 463035818_is_not_an_ai Jan 14 '22 at 12:37
  • Aha! Issue resolved! But I don't know how this 'const' magic resolved the issue – Waqar Ahmed Jan 14 '22 at 12:41
  • 1
    Think of `void f(int &x) { x=2; }`, which involves a non-const reference argument. We can call `f(y)` (and `y` will be assigned 2) but we can not call `f(1+1)`: the assignment `1+1=2` would make no sense. Hence, C++ forbids calling `f` with an rvalue expression like `1+1`. If we had instead `void f(const int& x) {...}` then C++ would allow `f(1+1)` since `x` is constant, and in the `...` we can not assign it. Hence, a copy ctor should always take a const reference `T(const T& other)` so that is can also be called with rvalue expressions of type T. – chi Jan 14 '22 at 12:54
  • @WaqarAhmed You should definitely invest in some [good C++ books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Jason Jan 14 '22 at 12:56
  • 1
    *Can a copy constructor have a non-const lvalue parameter?* **Yes**, however then that precludes using a temporary as an argument. General guidance for reference parameters is: if the object parameter is not being modified, then prefer using a *const reference* which allows the argument to be an lvalue or an rvalue. – Eljay Jan 14 '22 at 14:45
  • Much gratitude to everyone who contributed. Almost all responses prompted me to learn about rvalue/lvalue thing in c++, which is crucial to properly understand what's wrong with my code. – Waqar Ahmed Jan 14 '22 at 17:22

2 Answers2

2

The answer to the question in the title is: yes, the copy-constructor can have a non-const argument. From the C++20 draft

11.4.4.2 Copy/move constructors [class.copy.ctor]

A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments

JHBonarius
  • 10,824
  • 3
  • 22
  • 41
0

The problem is that the add member function returns an rvalue expression of type Complex and you're trying to bind a non-const lvalue reference Complex& to that rvalue.

You can solve this error by replacing Complex(Complex &c) with:

Complex(const Complex &c) //const added here

Note the const added in the above statement. Now, the parameter of the copy constructor is a reference to const Complex which can be bound to an rvalue.

Jason
  • 36,170
  • 5
  • 26
  • 60