Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the copy ctor used in this code?

class A
{
 public:
  A(const int n_);
  A(const A& that_);
  A& operator=(const A& that_);
};

A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }

A::A(const A& that_)    // This is line 21
{ cout << "A::A(const A&)" << endl; }

A& A::operator=(const A& that_)
{ cout << "A::operator=(const A&)" << endl; }

int foo(const A& a_)
{ return 20; }

int main()
{
  A a(foo(A(10)));    // This is line 38
  return 0;
}

Executing this code gives o/p:

A::A(int), n_=10
A::A(int), n_=20

Apparently the copy constructor is never called.

class A
{
 public:
  A(const int n_);
  A& operator=(const A& that_);
 private:
  A(const A& that_);
};

However, if we make it private, this compile error occurs:

Test.cpp: In function ‘int main()’:
Test.cpp:21: error: ‘A::A(const A&)’ is private
Test.cpp:38: error: within this context

Why does the compiler complain when it doesn't actually use the copy constructor?
I am using gcc version 4.1.2 20070925 (Red Hat 4.1.2-33)

like image 372
AngryWhenHungry Avatar asked May 28 '09 07:05

AngryWhenHungry


3 Answers

Core defect 391 explains the issue.

Basically, the current C++ standard requires a copy constructor to be available when passing a temporary of class type to a const reference.

This requirement will be removed in C++0x.

The logic behind requiring a copy constructor comes from this case:

C f();
const C& r = f(); // a copy is generated for r to refer to
like image 172
James Hopkin Avatar answered Sep 28 '22 10:09

James Hopkin


The 2003 standard, in §12.2/1, states:

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. ]

There are similar examples around. From what I gather, the compiler is free to generate temporaries or optimize them away.

like image 23
aib Avatar answered Sep 28 '22 10:09

aib


As far I see you are not using the copy constructor anywhere. In the statement foo(A(10)) you are creating a temporary object of class A and passing it as a const-reference to foo. The foo returns an integer which is used in the construction of object a. Hence I don't see where the copy constructor is getting involved here and how NRVO comes into picture. Also, I compiled the following code by making the copy constructor private and it compiled fine in VS2008.

using namespace std;

class A
{
 public:
  A(const int n_);
 private:
  A(const A& that_);
  A& operator=(const A& that_);
};

A::A(const int n_)
{ cout << "A::A(int), n_=" << n_ << endl; }

A::A(const A& that_)    // This is line 21
{ cout << "A::A(const A&)" << endl; }

A& A::operator=(const A& that_)
{ 
    cout << "A::operator=(const A&)" << endl; 
    return *this;
}

int foo(const A& a_)
{ return 20; }


int main(int argc,char *argv[])
{
   A a(foo(A(10)));    // This is line 38
  return 0;

}   
like image 41
Naveen Avatar answered Sep 28 '22 09:09

Naveen