Search code examples
c++classcopy-constructor

my class has no suitable copy constructor - depending if the argument of the constructor is const or not


Question:

I am learning c++, and i created a class to represent complex numbers. I created a copy constructor with the format

complex(const complex &c);

and the program worked fine.

Then, i removed the const (so it became: complex( complex &c); ) and the program doesn't work. It gives me this error:

"message": "class \"complex\" has no suitable copy constructor"

and it refers to the add method. The add method is this:

complex complex::add(complex &c){
    return complex( re + c.re, im + c.im);
};

If i do not add this method (and methods that generally return a complex number that is created in the return line, like this: return complex (integer_variable_Re, integer_variable_Im) ) the program works fine. When i add these kinds of methods, it throws me the error. I cannot understand why this doesn't work, as it should call the constructor that takes two integers and not the copy constructor.

Specs: Ubuntu: 20.04Lts

IDE: VScode

Compliler: G++ 9.4

(it says somewhere this: GNU C17 (Ubuntu 9.4.0-1ubuntu1~20.04.1) version 9.4.0 (x86_64-linux-gnu) compiled by GNU C version 9.4.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP, do not know if it it the compliler standard.)

Whole error message: [{ "resource": "/home/papaveneti/Documents/Programming/LearnCpp/complex_classStack.cpp", "owner": "C/C++", "code": "334", "severity": 8, "message": "class \"complex\" has no suitable copy constructor", "source": "C/C++", "startLineNumber": 48, "startColumn": 12, "endLineNumber": 48, "endColumn": 19 }]

Whole program:

#include <iostream>
#include <math.h>

using namespace std;

class complex {

public:
    complex (double r, double i); // constructor
    // only method that does not specify type
    
    //default constructor
    complex (); 

    //copy cosntructor
    complex( complex &c);

    // methods: 
    complex add(complex &c);
    void norm1();

private:
    // fields:
    double re, im; 
    double norm;
};

//constructor does not need to name a type
complex::complex(double r=0.0, double i=0.0){ // default values are 0
    re = r; im = i; 
    norm1();
};

complex::complex(){
    re=im=0;
}

complex::complex( complex &c){
    re=c.re;
    im=c.im;
}

void complex::norm1(){
    norm = sqrt(re*re + im*im);
};

complex complex::add(complex &c){
    return complex( re + c.re, im + c.im);
};

int main(){
    complex c1(3,4), c2(1,2);

    return 0;
}

Solution

  • Before C++17, the following line

    return complex( re + c.re, im + c.im);
    

    actually includes two object creations. First an unnamed temporary object is constructed using two double parameters. Then a copy of this object is made to where the return value is stored. This second copy is the reason for your compiler error. A copy constructor can only be used to copy a temporary object, if it is declared like this:

    complex(const complex&);
    

    If you omit the const qualifier, you cannot pass a temporary object.

    With the introduction of mandatory copy elision in C++17, there is no copy (or move) involved in the line mentioned above. Thus your program compiles fine. Your compiler, which is rather old, does not use C++17 by default and so refuses to compile the program.

    To solve your problem, you could either

    • use a copy constructor which takes a const reference
    • add a move constructor
    • use C++17 (either by using a newer compiler version or by passing the --std=c++17 command line option to your compiler

    Edit:
    You should also fix the problem that @Jason Liam mentions in this answer. As mentioned there, your program is ill-formed and should not compile even with the const constructor.