Consider the following code:
class A {
A(const A&);
public:
A() {}
};
int main() {
const A &a = A();
}
This code compiles fine with GCC 4.7.2, but fails to compile with Visual C++ 2010 with the following error:
test.cc(8) : error C2248: 'A::A' : cannot access private member declared in class 'A'
test.cc(2) : see declaration of 'A::A'
test.cc(1) : see declaration of 'A'
So is it necessary to have a copy constructor accessible when binding a temporary to a reference?
This is somewhat related to my previous question:
Is there a way to disable binding a temporary to a const reference?
So is it necessary to have a copy constructor accessible when binding a temporary to a reference?
Post C++11 - No
Pre C++11 - Yes.
This code compiles fine with GCC 4.7.2 because it is compliant with the C++11 standard.
C++11 standard mandates that when a const reference is initialized from prvalue
, it must be bound directly to the reference object and no temporary is permitted to be created. Also, the copy constructor is not used or required.
Prior to C++11 the rules were different. And this behavior(whether copy constructor will be called) is implementation defined. C++03 allowed the copy constructor being called while binding a const reference to an temporary and hence post C++11 the copy constructor needs to be accessible. Visual C++2010 adheres to the C++03 standard.
Section 8.5.3.5 of the C++03 standard states that this is implementation-defined:
If the initializer expression is an rvalue, with T2 a class type, and "cv1 T1" is reference-compatible with "cv2 T2," the reference is bound in one of the following ways (the choice is implementation-defined):
-- The reference is bound to the object represented by the rvalue (see 3.10) or to a sub-object within that object.
-- A temporary of type "cv1 T2" [sic] is created, and a constructor is called to copy the entire rvalue object into the temporary. The reference is bound to the temporary or to a sub-object within the temporary.
The constructor that would be used to make the copy shall be callable whether or not the copy is actually done.
So it appears that both implementations are consistent with the C++03 standard.
The last sentence is a little confusing, but the way I read it, it means that the implementation may choose the second way, but still optimize away the copy. In that case, the copy constructor would have to be accessible even though the copy wasn't actually done, similar to return value optimization.
With the C++11 standard, the second way is no longer an option.
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