C++ – Copy Constructor Needed with temp object

ccopy-constructor

The following code only works when the copy constructor is available.

When I add print statements (via std::cout) and make the copy constructor available it is not used (I assume there is so compiler trick happening to remove the unnecessary copy).

But in both the output operator << and the function plop() below (where I create a temporary object) I don't see the need for the copy constructor. Can somebody explain why the language needs it when I am passing everything by const reference (or what I am doing wrong).

#include <iostream>

class N
{
    public:
        N(int)  {}
    private:
        N(N const&);
};

std::ostream& operator<<(std::ostream& str,N const& data)
{
    return str << "N\n";
}

void plop(std::ostream& str,N const& data)
{
    str << "N\n";
}

int main()
{
    std::cout << N(1);     // Needs copy constructor  (line 25)
    plop(std::cout,N(1));  // Needs copy constructor

    N    a(5);
    std::cout << a;
    plop(std::cout,a);
}

Compiler:

[Alpha:~/X] myork% g++ -v
Using built-in specs.
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5646~6/src/configure –disable-checking –enable-werror –prefix=/usr –mandir=/share/man –enable-languages=c,objc,c++,obj-c++ –program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ –with-slibdir=/usr/lib –build=i686-apple-darwin10 –with-gxx-include-dir=/include/c++/4.2.1 –program-prefix=i686-apple-darwin10- –host=x86_64-apple-darwin10 –target=i686-apple-darwin10
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5646)

[Alpha:~/X] myork% g++ t.cpp
t.cpp: In function ‘int main()’:
t.cpp:10: error: ‘N::N(const N&)’ is private
t.cpp:25: error: within this context
t.cpp:10: error: ‘N::N(const N&)’ is private
t.cpp:26: error: within this context

This is a simplified version of some real code.
In the real code I have a class that contains a std::auto_ptr. This means that a copy constructor that takes a const reference is not valid (without some work) and I was getting an error indicating that the copy constructor was not available because of it:

Change the class too:

class N
{
    public:
        N(int)  {}
    private:
        std::auto_ptr<int>  data;
};

The error is then:

t.cpp:25: error: no matching function for call to ‘N::N(N)’

Best Answer

From http://gcc.gnu.org/gcc-3.4/changes.html

When binding an rvalue of class type to a reference, the copy constructor of the class must be accessible. For instance, consider the following code:

class A 
{
public:
  A();

private:
  A(const A&);   // private copy ctor
};

A makeA(void);
void foo(const A&);

void bar(void)
{
  foo(A());       // error, copy ctor is not accessible
  foo(makeA());   // error, copy ctor is not accessible

  A a1;
  foo(a1);        // OK, a1 is a lvalue
}

This might be surprising at first sight, especially since most popular compilers do not correctly implement this rule (further details).

This will be fixed in C++1x by Core Issue 391.

Related Topic