#include <iostream>
class A {
public:
A(){ cerr << "A Constructor" << endl; }
~A(){ cerr << "A Destructor" << endl; }
A(const A &o){ cerr << "A Copy" << endl; }
A& operator=(const A &o){ cerr << "A Assignment" << endl; return *this; }
};
class B : public A {
public:
B() : A() { cerr << "B Constructor" << endl; }
~B(){ cerr << "B Destructor" << endl; }
private:
B(const B &o) : A() { cerr << "B Copy" << endl; }
B& operator=(const B &o){ cerr << "B Assignment" << endl; return *this; }
};
int main() {
A a;
const A &b = B();
return 0;
}
In GCC 4.2, I get this message:
In function 'int main()':
Line 16: error: 'B::B(const B&)' is private
compilation terminated due to -Wfatal-errors.
If I remove the "private" from B, I get the output I expect:
A Constructor
A Constructor
B Constructor
B Destructor
A Destructor
A Destructor
My question is: why does making a method which isn't called private change whether this code compiles? Is this standard-mandated? Is there a workaround?
The important verbiage in the current standard (C++03) seems to be in §8.5.3, which explains how references are initialized (In these quotes,
T1
is the type of the reference being initialized andT2
is the type of the initializer expression).So, even if the implementation binds the reference directly to the temporary object, the copy constructor must be accessible.
Note that this is changed in C++0x, per the resolution of CWG defect 391. The new language reads (N3092 §8.5.3):
The first case applies and the reference is "bound directly" to the initializer expression.
So what you're using is 'copy-initialization':
In 13.3.1.3 "Initialization by constructor", the overloads for the constructor chosen are:
So, for copy-initialization, the copy constructor must be available. However, the compiler is permitted to 'optimize away' the copy:
12.2/1 Temporary objects
You can get the effect you want by avoiding copy-initialization and using direct-initialization:
Note:
Since newer versions of GCC apparently have a different behavior, I thought I'd post this note, which might address the difference (with both behaviors still standards conforming):
8.5.3/5 References says:
I originally read the last sentence ("the constructor that would be used...") to apply to both options, but maybe it should be read as only applying to the seconds option - or at least maybe that's how the GCC maintainers are reading it.
I'm not sure if this is what's going on between the differing behavior of GCC versions (comments welcome). We're definitely reaching the limits of my language-lawyering skills...
I think it is indeed a compiler bug, gcc seems to think that is is copy initialization. Use direct initialization instead:
The copy-constructor call in copy initialization is always optimized away (an instance of copy elision), and then doesn't have to be available.