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;
}
2
Answers
Before C++17, the following line
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: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
const
reference--std=c++17
command line option to your compilerEdit:
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.The program is ill-formed in all C++ versions and gcc and msvc are wrong in accepting the code because while defining the constructor
complex::complex(double r, double)
outside the class you’re providing default arguments for both of the parameters which turns it into a default constructor. This is not allowed and clang rejects it.From default arguments documentation:
(emphasis mine)
To solve this you have to make sure that you don’t add these default arguments while implementing the ctor outside the class so that you avoid turning it into a default ctor. Additionally, if you’re using C++11 or C++14 then you must add a low-level const to the parameter of the copy ctor as there was no mandatory copy elision prior to C++17.
Here is the gcc bug:
GCC accepts ill-formed out of class definition program
Here is the msvc bug:
MSVC accepts invalid program involving default arguments inside constructor