Reputation: 115
This is a followup of this question
in the following code, why does line 1 compiles while line 2 and 3 does not (using visual C++ 2010)
class ABase
{
protected:
ABase() {}
~ABase() {}
private:
ABase( const ABase& );
const ABase& operator=( const ABase& );
};
class A : ABase
{
};
class B
{
public:
B() {}
~B() {}
private:
B( const B& );
const B& operator=( const B& );
};
int main( void )
{
A a = A(); // line 1
A a2( a ); // line 2
B b = B(); // line 3
return 0;
}
(note BA is a copy of boost::noncopyable)
edit: My problem is not to know why line 2 and 3 does not compile (I know that, the copy constructor is private), but why line 1 does.
Upvotes: 8
Views: 9511
Reputation: 153919
Why does line 1 compile? Because your compiler is broken; it shouldn't,
according to the standard. While your class A
has an implicitly
declared copy constructor, §12.8/7 of the standard states that An
implicitly-declared copy constructor will be implicitly defined if it is
used to initialize an object (as in A a = A();
), and that a program is
ill formed (and thus requiring a diagnostic) if the constructor is
implicitly defiend and a base class has an inaccessible or ambiguous
copy constructor. There's even a note saying this is the case even if
the implementation elides the copy constructor. You're compiler is not
going far enough: it sees the implicitly declared public copy
constructor, but it doesn't try to implicitly define it, even though the
standard clearly says it should.
Upvotes: 1
Reputation: 208353
The compiler is wrong in accepting the first use. Even if the copy is elided, the copy constructor must be accessible for the code to be correct.
In this particular case there is an implicitly declared copy constructor in A
:
§12.8/4 If the class definition does not explicitly declare a copy constructor, one is declared implicitly.
That is implicitly defined:
§12.8/7 An implicitly-declared copy constructor is implicitly defined if it is used to initialize an object of its class type from a copy of an object of its class type or of a class type derived from its class type108). [Note: the copy constructor is implicitly defined even if the implementation elided its use (12.2). ] A program is ill-formed if the class for which a copy constructor is implicitly defined has:
— a nonstatic data member of class type (or array thereof) with an inaccessible or ambiguous copy constructor, or
— a base class with an inaccessible or ambiguous copy constructor.
Upvotes: 5
Reputation: 206536
ABase( const ABase& );
The copy constructor is made private so a copy of the class object cannot be created using this private copy constructor resulting in error.
A a = A(); // line 1
Uses the A::A(const A&)
to create a new A
object. A
is derived from ABase
and it calls
ABase::ABase(const ABase&)
in its constructor, which is private to it wont compile either.
Here is the output on Ideone. It doesn't compile even on gcc.
Why it works on Visual studio?
The reason is a possible Return Value optimization by the visual C++ compiler which elides the copy constructor.
As per the C++ standard, 12.8 copying class objects section 15
When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects. In such cases, the implemen-tation treats the source and target of the omitted copy operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.111)
See my answer here which cites the Standard and the example code in this regard.
A a2( a ); // line 2
Does not compile for the same reason that ABase::ABase(const ABase&)
is private.
B b = B(); // line 3
Does not compile because B( const B& );
is private.
Upvotes: 2
Reputation: 114491
Indeed line 1 should not compile.
Apparently vc++2010 has problems enforcing language rules in this case (may be because they're related to a base class and not to the object itself).
g++ diagnostic message about line 1 is very clear
ncopy.cpp: In copy constructor ‘A::A(const A&)’:
ncopy.cpp:7: error: ‘ABase::ABase(const ABase&)’ is private
ncopy.cpp:12: error: within this context
ncopy.cpp: In function ‘int main()’:
ncopy.cpp:27: note: synthesized method ‘A::A(const A&)’ first required here
Upvotes: 6
Reputation: 12932
Line 1 is a return value optimization (the compiler sees that there is no need to create a temporary variable for A()
and use the copy constructor/assignment operator to assign to variable a
). However, this does not compile on GCC (version 4.2.1) and should be avoided.
Line 2 does not compile because the compiler isn't generating an assignment operator for you in this case. Line 3 is not compiling, as you expect.
Reagan summary: line 1 works because it's Microsoft, the others behave as expected.
Upvotes: 1
Reputation: 54325
I believe it is because the constructor is protected, not private. The compiler provided constructor in class A is free to call the protected constructor of class ABase, so it works.
Also, line 1 is not a copy constructor. A declaration with an assignment is a special case which is converted into a constructor.
Upvotes: 0