infokiller
infokiller

Reputation: 3126

Why is the compiler bugging me on this one?

(using Visual C++ 2010, compiling in debug with optimizations turned off)

I have the following very simple class:

class exampleClass
{
public:
    exampleClass()
    {
        cout << "in the default ctor" << endl;
    }
private:
    exampleClass (const exampleClass& e)
    {
        cout << "in the copy ctor" << endl;
    }
};

When I try to compile it with the following main:

#include <iostream>
using namespace std;

int main()
{
    exampleClass e1=exampleClass();
    return 0;
}

I get the compilation error:

'exampleClass::exampleClass' : cannot access private
                               member declared in class 'exampleClass'

When I remove the access modifier "private" from the copy ctor, the program compiles and prints only:

in the default ctor

Why is this happening? If the compiler will not invoke the copy ctor anyway, why is it bugging me?

Since some people missed the first line (at least before some edits) i will repeat it:

I compiled in debug with optimizations turned off.

Upvotes: 17

Views: 1046

Answers (9)

ali_bahoo
ali_bahoo

Reputation: 4863

Everyone explains how you should instantiate an object and @Grigory Javadyan makes a good point on copy elision. It looks like, MSVC does this optimization (so called return value optimization) even in debug mode.

exampleClass e1=exampleClass();

is the same as

exampleClass giveExample()
{
  return exampleClass();
}

exampleClass e1 = giveExample();

You will see that copy ctor will not be called.

But here :

exampleClass giveExample()
{
  exampleClass example;
  return example;
}

exampleClass e1 = giveExample();

you will see another output line :

in the copy ctor

Because you are forcing the compiler to first generate an object and then return it.

Here, here and here some questions I can find, similar to yours.

PS. Link#2 is from another Q&A site. I hope this is not a problem.

Upvotes: 1

user500944
user500944

Reputation:

This type of initialization is called copy-initialization. I believe the following clause from the C++11 standard applies here (paragraph 8.5.16, page 204):

If the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated (13.3.1.3), and the best one is chosen through overload resolution (13.3). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.

In this case, the best applicable constructor is the copy ctor, which is private, hence the error message.

To further answer your question, when the copy ctor is private, your program is simply not allowed to pass the complier check because of the rules imposed by the standard. When you make the copy ctor public, the program becomes valid, but the call to the copy ctor is optimized away.

EDIT: Okay, to elaborate on previous paragraph.You're dealing here with the so-called copy elision. While the copy elision is possible in this case, the standard requires you to provide an accessible copy ctor for your class.

Upvotes: 16

StevieG
StevieG

Reputation: 8709

Its because the copy constructor is private..

your code is

  • creating a temporary exampleClass and invoking the default constructor exampleClass()
  • attempting to assign the resulting temporary object to e1 using the private copy constructor

Upvotes: 0

AndersK
AndersK

Reputation: 36082

when you write

exampleClass e1 = exampleClass() 

it is the same as writing

exampleClass e1( exampleClass() );

which invokes the copy ctor.

Upvotes: 0

Vite Falcon
Vite Falcon

Reputation: 6645

This is because at compile time, the compiler checks if the function the user is trying to access is really accessible. So when you use exampleClass e1=exampleClass();, it first checks if the copy-constructor is accessible. It spits out an error because the copy-constructor is not private. Remember that at this point the compiler hasn't gone onto the optimization stage where it does the clever stuff as to skip the copy-constructor.

When you make the copy-constructor public, the compiler successfully goes through the stage of parsing the code and making sure that everything is accessible and is in order (there's actually more than that going on) and then at the optimization stage, which usually is on in 'Release' mode it does the clever stuff and by-passes the use of copy-constructor. However if you tried the same code in 'Debug' mode you'd see that the copy-constructor does get called.

Upvotes: 1

orlp
orlp

Reputation: 117661

exampleClass e1=exampleClass();

This will first create a temporary exampleClass using the default constructor and then copy that into e1 using the copy constructor. This will invoke the private copy constructor and thus give you the error. The corrent way to instantiate an instance of a class with the default constructor is this:

exampleClass e1;

Upvotes: 12

The compiler is required to bug you there. While the copy can be elided, the standard requires that the copy constructor is accessible for that type of construction. Of course, you can simplify the code and avoid the copy construction altogether:

exampleClass e1; // Will call exampleClass::exampleClass()

Upvotes: 4

Ricibob
Ricibob

Reputation: 7705

exampleClass e1=exampleClass();

is the same as:

exampleClass e1(exampleClass());

i.e it invokes the (private) copy constructor.

Upvotes: 1

Simone
Simone

Reputation: 11797

That's not how you do instantiate an object in C++. If you want it allocated on the stack, you write:

exampleClass e1;

and you're done, sincee exampleClass' constructor accepts no parameters.

Otherwise, if you want it allocated on the heap, you write:

exampleClass e1 = new exampleClass(); 

The way you wrote it actually creates a temporary object and invokates the copy constructor on that temporary object to create e1. Problem is that your copy-ctor is private, so the compiler's error message.

Upvotes: 0

Related Questions