Reputation: 157
I have the following c++ code (VS2013):
#include <iostream>
using namespace std;
class A {
int i;
public:
A(int i) : i(i) {
cout << "Constructor: " << i << endl;
}
A(const A &o) : i(o.i) {
cout << "Copy constructor: " << i << endl;
}
~A() {
cout << "Destructor: " << i << endl;
}
};
A test(const A &a, A b, A *c) {
return *c;
}
int main() {
A b(10);
cout << "START OF TEST" << endl;
test(1, b, &b);
cout << "END OF TEST" << endl;
system("pause");
}
When running the code, I get the following output between the "START OF TEST" and "END OF TEST" outputs:
Constructor: 1
Copy constructor: 10
Copy constructor: 10
Destructor: 10
Destructor: 10
Destructor: 1
3 objects are built: 1 using an integer 1
, and 2 using an object of class A
(with i = 10).
It's worth mentioning that when the test
function's argument const A &a
is changed to A &a
(not a constant), the program does not compile, giving the following error:
Error C2664: 'A test(A &,A,A *)' : cannot convert argument 1 from 'int' to 'A &'
How is this behavior explained?
Specifically:
Why does sending an integer 1
to test
make A's parameter constructor A(int i)
work (and only when const
is used)?
Why does A's copy constructor A(const A &o) work twice? (one run occurs when calling test
, and another when returning *c
).
Upvotes: 0
Views: 4189
Reputation: 7482
Well, calling test
with the first argument 1
causes the creation of a rvalue
of type A
. An rvalue can be assigned to a const lvalue reference
but not to a plain lvalue
reference. If you want it to compile without using const
you have to specify that the parameter is a rvalue
reference.
g++
error is a little bit more informative:
error: cannot bind non-const lvalue reference of type ‘A&’ to an rvalue of type ‘A’
test(A(1), b, &b);
rvalue
can be assigned to an rvalue reference
or to a lvalue reference to const
.Why is that? rvalues
are temporary objects or literals. If this code was legal
int &r
= 5
then you would be able to modify 5
.
On the other hand lvalue references to const
forbids any change to the object they reference and thus you may bind them to a rvalue
.
const A& x = 1; //compile
x = 2; //error!
A&& xxx = 1; //compile
A& xx = 1; //does not compile.
Regarding the second question. You are returning a copy of A
from test
so *c
triggers the construction of a copy of c
.
Try returning a reference A
from test
to see that the constructor is not called.
Upvotes: 7