snippet 1:
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
};
int main(){
C c1;
C c2 = c1;
return 0;
}
output: const copy constructor called
snippet 2:
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
C(C& c){
cout<<"non-const copy constructor called.\t "<<endl;
}
};
int main(){
C c1;
C c2 = c1;
return 0;
}
output: non-const copy constructor called
snippet 3:
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
C(C c){
cout<<"non-const copy constructor called.\t "<<endl;
}
};
int main(){
C c1;
C c2 = c1;
return 0;
}
output: error: copy constructor must pass its first argument by reference
I am so confused about:
C(const C& c)
, C(C c)
won't cause infinite recursion, why it still doesn't work?Snippet 1: One standard copy constructor with const T&
. Happy world.
Snippet 2:
What you have effectively done is overloaded the copy constructor - one that takes a reference T&
and the other that takes a constant reference const T&
.
Please note: Any constructor for a class T that has one mandatory argument of type T &
or const T &
(it may also have further, defaulted arguments) is a copy constructor.
So, for the compiler, it all just boils down to finding the Best Fit for overload resolution and it is done as:
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if:
- ....
- S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
So writing
C c1;
C c2 = c1;
will call the non-const copy constructor since it is a better match, but,
writing,
const C c1;
C c2 = c1;
will call the const copy constructor (you can check) since now the copy constructor with const is the only viable match.
Snippet 3 is just plain wrong for the compiler.
C(C c){
cout<<"non-const copy constructor called.\t "<<endl;
}
You can't have a method with a signature C(C c)
. The compiler thinks that you are trying to write a copy constructor and missed writing the &
and hence reports the error. Remove it and it works fine.
@Unless you have a very good reason, never ever use C(C& c)
for your copy constructor. Don't skip const
because mutating the object from which you are making a copy doesn't make much sense.
for snippet 2, why the non-const copy constructor here is valid? why non-const copy constructor was called, rather than the const one.
Consider your code for this question, but with the change below with the comment // (*)
:
int main(){
const C c1; // (*) <- See change here
C c2 = c1;
return 0;
}
This calls the const
copy ctor version. It really has nothing to do with the function happening to be a constructor - if a function has two overloads, one taking a reference, and one a const
reference, then non-const objects will be called with the first, and const
objects with the second.
for snippet 3, I know that copy constructor must use const reference to avoid infinite recursion. But Here class C has got C(const C& c), C(C c) won't cause infinite recursion, why it still doesn't work?
Consider the following code, and note that there is no invocation going on (the content of main
is pretty much erased).
#include<iostream>
using namespace std;
class C{
public:
C(){}
C(const C& c){
cout<<"const copy constructor called"<<endl;
}
C(C c){
cout<<"non-const copy constructor called.\t "<<endl;
}
};
int main(){
// Note that nothing is creating C instances at all.
return 0;
}
This results in the exact same error - the compiler simply refuses to compile a class with this interface, regardless of whether something is attempting to call it or not.
Quoting from an answer to this question "it's forbidden by the standard in §12.8/3:
A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv- qualified) X and either there are no other parameters or else all other parameters have default arguments.
"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With