Error when have private copy ctor with public assignment operator

Can one of you explain why the following piece of code does not compile?

#include <iostream>

using namespace std;

class Foo
{
public:
  Foo() { cout << "Foo::Foo()" << endl << endl; }
  Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; }
private:
  Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; }
};

int main()
{
  Foo foo;

  foo = Foo();
}

The error I receive:

$ g++ -o copy_ctor_assign copy_ctor_assign.cc && ./copy_ctor_assign
copy_ctor_assign.cc: In function 'int main()':
copy_ctor_assign.cc:10: error: 'Foo::Foo(const Foo&)' is private
copy_ctor_assign.cc:17: error: within this context

Note: when I remove the private: keyword the code compiles but the copy ctor is never called. So why does it err when it's private?

Not sure if it's important but I'm using:

$ g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)
Copyright (C) 2006 Free Software Foundation, Inc.
13.10.2009 15:32:21
FWIW: The code does compile if you assign a previously created Foo object instead of a temporary object. I.e. foo = bar; instead of foo = Foo();.
sepp2k 13.10.2009 15:47:35
6 ОТВЕТОВ
РЕШЕНИЕ

You are initializing a reference from temporary.
The standard states:
The temporary should be initialized (8.5.3 par 5)"using the rules for a non-reference copy initialization (8.5)".

The copy construction is removed for the temporary (permitted by the standard. 12.8 par 5).
However, the standard clearly states (12.2 par 1):
"Even when the creation of the temporary object is avoided (12.8), all the semantic restrictions must be respected as if the temporary object was created. [Example: even if the copy constructor is not called, all the semantic restrictions, such as accessibility (clause 11), shall be satisfied. ]"

(also, when looking for the right quote, found this duplicate :)

Edit: adding relevant location from the standard

5
23.05.2017 11:53:02
This answer is correct, but you quote the wrong part of 8.5.3 para 5 (in our case, we have class types and reference compatible types, so the previous bullets should be taken). The important one is the previous one and it says whether to copy or not is implementation defined and then "The constructor that would be used to make the copy shall be callable whether or not the copy is actually done.". For C++0x, the implementation is not allowed to copy anymore, and will not require a copy constructor anymore.
Johannes Schaub - litb 13.10.2009 21:43:13

Copy Ctor is called when:

  1. passing an object by value as parameter to a function,
  2. returning an object from a function.

So you are certainly doing one or both of these case somewhere in your code. You should set Copy Ctor as public or avoid the 2 previous cases.

1
13.10.2009 15:38:29
He did. Try to compile his code. The error is raised (without any additional code)
Oren S 13.10.2009 16:15:35

Copy constructor would be called if you write

Foo foo; // normal constructor
Foo foo1(foo); //copy constructor

In your case, first the default constructor is called and then the operator= method.

0
13.10.2009 15:39:31

Assuming that the code you've posted is the only code in the project, and there's no covert passing of Foos by value going on anywhere, all I can figure is that gcc is optimizing

Foo foo;
foo = Foo();

to

Foo foo = Foo();

...which is unsound, as the first form is a default-construct and an assignment, while the second is equivalent to

Foo foo(Foo());

...which is clearly a copy construction. If I'm right, the copy constructor is not being run because GCC can optimize away the redundant temporary; this is permitted by the C++ spec.

In general, it is not a good idea to have assignment operators and copy constructors at different protection levels; as you've seen, the results can be unintuitive.

3
13.10.2009 15:42:25
gcc can't optimize the constructors like that, since they have side effects (the couts). If gcc does that, it's a bug.
CAdaker 13.10.2009 15:50:27
@CAdaker: nope. Removing redundant temporaries is a special case and the C++ standard explicitly allows eliding copy construction under such circumstances.
Konrad Rudolph 13.10.2009 15:52:41
Even when the temporaries have non-trivial constructors and destructors? That sounds completely insane.
CAdaker 13.10.2009 15:57:29
I tried to compile his code with -O0 (no optimization). same problem. And when the "public:" is removed the copy C'tor is not called at all. I can't figure it out but it doesn't look like an optimization. Otherwise the copy C'tor should have been called...
Oren S 13.10.2009 16:19:48
GCC can optimize whatever it wants, but it can't violate the as-if rule. There's ansolutely no way it can suddenly strat requiring a copy constructor for the code which didn't require one under the "canonical" (non-optimized) interpretation.
AnT 13.10.2009 17:19:14

That code compiles with gcc 4.3.3 and 4.4.1. Maybe that's just a bug in gcc 4.1?

4
13.10.2009 15:48:36
Can you try to recompile in these versions using -Wall? Thanks
Oren S 13.10.2009 16:47:22
I get warnings about operator= not returning a value, but otherwise nothing.
CAdaker 13.10.2009 16:54:07
It fails for me: using g++ (GCC) 3.4.4
Martin York 13.10.2009 18:54:31
Not a bug but required for c++03
Johannes Schaub - litb 13.10.2009 21:35:44
#include <iostream>

using namespace std;

class Foo
{
public:
  Foo() { cout << "Foo::Foo()" << endl << endl; }
  Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; }
  Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; }
};

int main()
{
  Foo f1;// default constructor called

  Foo f2 = f1; //copy constructor called
}

Check this, in Foo f2=f1; ( f2 is created using copy constructor)

-1
13.10.2009 15:51:00
What are you trying to say in the above code? The question was asked why it is getting compilation error when the copy constructor is private. You just gave an example of default constructor and copy constructor.
Jagannath 13.10.2009 16:01:43