7

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?

Community
  • 1
  • 1
vitaut
  • 49,672
  • 25
  • 199
  • 336

3 Answers3

4

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.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • "And this behavior was implementation defined" is a bit misleading. The actual copying or not was implementation defined, but the C++03 standard required an accessible copy constructor. – Cheers and hth. - Alf Dec 16 '12 at 06:06
  • 1
    "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." us a bit misleading. It holds only when the types are such that direct binding is possible. In other words, the rules do not preclude a conversion. – Cheers and hth. - Alf Dec 16 '12 at 06:09
2

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.

Community
  • 1
  • 1
Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
  • 4
    C++03 has been superseded by C++11 and the rules have changed in C++11. – James McNellis Dec 16 '12 at 05:16
  • @Vaughn Cato: the only thing is that your last statement contradicts with the last statement from the standard that you cite. IIUC the standard says that the copy ctor should be available in both cases, so GCC might be using the rules from the new standard or its a bug. – vitaut Dec 16 '12 at 05:23
  • @vitaut: The way I read it, it just means that if the implementation chose to use the second way, then the copy constructor would have to be available, even if the copy was actually elided. That is, the implementation could decide that copies were logically necessary, but still optimize away the actual copy. – Vaughn Cato Dec 16 '12 at 05:30
0

Visual C++ is incorrect; the Standard does not indicate that the copy constructor must be accessible to bind a const reference to a temporary.

Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249