1

I am learning C++, and this is my first attempt to understand how copy constructors work:

class Cents
{
private:
    int m_nCents;
public:
    Cents(int nCents=0)
    {
        m_nCents = nCents;
    }

    // Copy constructor
    Cents(  Cents cSource)
    {
        m_nCents = cSource.m_nCents;
    }
};

int main()
{
 Cents cMark(5); // calls Cents constructor
 Cents cNancy = cMark; // calls Cents copy constructor!
 return 0;
}

But I get this error:

Error 1 error C2652: 'Cents' : illegal copy constructor: first parameter must not be a 'Cents'

What is wrong in my copy constructor?

I checked that if in the constructor I pass the parameter by reference, then it is compiling well, but won't work in the way I am doing. Why it is like that?

Mat
  • 202,337
  • 40
  • 393
  • 406
gpuguy
  • 4,607
  • 17
  • 67
  • 125
  • 6
    Because to pass an object *by value* it has to be copied. But the copy-constructor is there to do that copy for you. So in order to call the copy-constructor it would have to already been executed. – Bernd Elkemann Jan 25 '15 at 07:23
  • 2
    Passing by value requires the object to be copied. With the copy constructor. Which copies the object with the copy constructor. Which passes the object by value so requires the copy constructor. Which passes the object by value so requires the copy constructor. Which passes the object by value so requires the copy constructor. Which passes the object by value so requires the copy constructor.... Kaboom. You get to see this website's name. – Hans Passant Jan 25 '15 at 08:26
  • 1
    @eznme I find your comment-answer more insightfull than any of the given answers so far. – D Drmmr Jan 25 '15 at 08:53

3 Answers3

4

Passing any parameter by value requires a copy constructor - either explicit or implicit. When we define a copy constructor we mean we don't want to use an implicit copy constructor. Using the defined copy constructor for the copy constructor will create a circular dependency.

Ophir Yoktan
  • 8,149
  • 7
  • 58
  • 106
  • The problem is not the "circular dependency", but the resulting infinite recursion – Emilio Garavaglia Jan 25 '15 at 07:47
  • Technically, you could allow this in compile time, and you will indeed get an infinite recursion. But logically, you have a circular dependency – Ophir Yoktan Jan 25 '15 at 07:49
  • Yes, but the point is that circular dependency between functions are not "the" problem for the compiler. The problem is what you get from it in this particular case (and that the compiler inhibits to happen). If what you said is true, then no circular call can ever be done. But that's not true: recursion is one of the fundamental formalism of programming. – Emilio Garavaglia Jan 25 '15 at 07:56
3

just as the last answer

if you use the following statements:

Cents c1 ;
Cents c2(c1) ;

or pass your object to a function by value like this:

void Func (Cents c) {}

int main() { 
    Cents c1 ;
    func (c1);
}

or use assignment operator to initialize your object:

Cents c2 = c1 ;

compiler will search for copy constructor and it will find that Cents( cents csource) (your proposed copy constructor)also pass the object by value. Technically to pass by value you ask the compiler to make a temporary copy of the object in the function body. So it is not logic to ask the copy constructor itself to call the copy constructor which would be a recursive call

youssef
  • 613
  • 4
  • 16
  • 2
    right, except i would not call `Cents c2 = c1 ;` *assignment*: It is just a way to write initialization (ie copy *construction*) whereas `c2 = c1` is assignment. – Bernd Elkemann Jan 25 '15 at 08:15
  • 2
    `Cents c2 = c1 ;` is not assignment, it is initialization. (Copy-initialization, to be precise). `=` is not the assignment operator in this context. – M.M Jan 25 '15 at 08:26
  • ya, thank you. that's right, I meant assignment opperator in general – youssef Jan 25 '15 at 08:26
  • The copy constructor is not used when the assignment operator is used; the copy-assignment constructor is used there :) – M.M Jan 25 '15 at 08:28
2

I checked that if in the constructor I pass the parameter by reference, then it is compiling well, but won't work in the way I am doing. Why it is like that?

You are defining how to make a copy of Cents.

You must take a reference parameter because if you try to take that parameter by value, that value would be a copy.

Your copy constructor cannot require an already-defined copy constructor.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180