foke
foke

Reputation: 115

private copy constructor/assignment operator and copy-initialization

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

Answers (6)

James Kanze
James Kanze

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

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

Alok Save
Alok Save

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

6502
6502

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

larsmoa
larsmoa

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

Zan Lynx
Zan Lynx

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

Related Questions