Solved

All about copy constructor

Posted on 1999-01-20
17
285 Views
Last Modified: 2010-08-05
Hello friends,

I have read a lot about copy constructor. The more I read
the more confused I become. What exactly is a copy constructor? What is the use of a Copy Constructor and how does it work?

How does the compiler know when to call a copy constructor or the regular one?

Thanks for not proposing links.




0
Comment
Question by:Diana_pal
  • 5
  • 5
  • 5
  • +1
17 Comments
 

Accepted Solution

by:
koskia earned 70 total points
Comment Utility
I'll try to make it easy to understand:

* I'll refer to class A:

1. as you know a class may have several constructors.
    the difference between each of the constructors, is in the
    kind of parameters that are passed to it.

    A(int num);
    A(int num2); // wrong, same parameters

    A(int num);
    A(A other);  // right

2. a copy constructor is defined as follows:
    A(A& other);
    a costructor, that gets a reference to another object of the
    same class.

3. there is no other copy constructor.

4. the compiler generates automatic functions for each class,
    unless the programmer generated this function himself:
    a. Copy Constructor.
    b. Assignment operator.
    along with some other functions.

5. if the programmer wrote a copy constructor himself:
    class A {
    public:
        A(A& other);
    }

    the compiler will always call the programmers copy constructor and actually won't even generate a different one for the specific class.

6. the copy constructor may be called in different occasions:
    a. the basic one is when you use it directly, creating an
        object of your class:
        A a1;
        A a2(a1); // assignment operator called
     b. the second one is when generating an object of your
         class using the = sign:
        A a1;
        A a2 = a1; // assignment operator called
     c. the third one is when you pass a parameter to a function and you pass it by value:
     
      * all parameters in C and C++ are passed by value, when you pass a pointer or a reference this is duplicated too.
I'll explaing.

void func1(A* a1);
or
void func2(A& a2);

are used in some other function main:
main()
{
   A a1, a2;
   func1(&a1);
   func2(a2);
}
in both cases there is a temporary variable which represents a1 and a2 at func1 and func2.
but the temporary variable is fixed (a pointer or reference always have the same size and the duplication is preknown)

but!!
when your function deals with real objects:
func3(A a3);

main()
{
  A a3;
   func3(a3);
}

when the compiler calls funcs from within main, it must make a copy from a3 (because all c and c++ parameters are passed by value).
for creating a new object he must use a constructor.
the only constructor he can use is the copy constructor described above, doing this at this matter:
A func3's a3( & main's a3);

d. the last situation when the compiler calls a copy constructor is when it returns an entire object as return value:
A func4();

it's done so for the same reason, all c and c++ return values are passed by value, and that's actually have a good reason,
after something is returned by a fuctions, the function ends, and the original object doesn't exists anymore, so the compiler must copy it.
again, copy constructor is the answer.

7. so, for the last question, why is it needed, I'll illustrates with an example:

class A {
   public:
    A(int num);
    ~A();
    int* n_num;
}

A::A(int num)
{
    p_num = new int(num);
}

A::~A()
{
    delete p_num;
}

this is a very simple class with a pointer to int, it creates it in his constructor, and deletes it in the destructor.
let's use it in main:

void func5(A a);
main()
{
   A a1(5);
   func5(a1);
}

this program may crash on many systems, and why:
when a1 is created there is a dynamic allocation for 1 pointer to int.

when calling func5 with a1, a temporary object is created from main's a1 into func5's a, because there is no default constructor defined in class a, a bitwise operation takes place:

func5's a, now looks exactly like main's a1:
a's p_num points to where a1's p_num points.
when the temporary a is destroyed (leaving the function),
a's destructor is called, and the memory pointed by a's p_num is deleted!!!!
but a1's p_num still points to the same place, but not there's junk in there.

THIS IS THE MAIN REASON FOR WRITING A COPY CONSTRUCTOR, POINTER INITIALIZATION AND DESTRUCTION

when main exits, a1's p_num destructor is also called, and now the delete function try to delete an already deleted memory, where on most systems crashes the program.

that's it the truth on one leg.

you should always write a constructor and assignment operators when your class includes pointers and pointers initialization.

the right way to write class A:

class A {
   public:
      A(int num);
      A(A& other);
      A& operator=(A& other);
      ~A();
     
    private:
    int* p_num;
}

A::A(int num)
{
   p_num = new int(num);
}

A::operator=(A& other)
{
   if (this == &other)  // checking for self
       return;

    p_num = new int(*other.p_num); // now points to another
                                                        // place in memory
}

A::~A()
{
   delete p_num;
}

// Assignment operator //

A::A(A& other)
{
    p_num = new int(*other->pnum);
}


I hope this is a answer you wanted.
asaf

0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
koskia's answer, while very clear in most places, gets a little confussing in the section
*******************************
6. the copy constructor may be called in different occasions:
       a. the basic one is when you use it directly, creating an
           object of your class:
           A a1;
           A a2(a1); // assignment operator called
        b. the second one is when generating an object of your
            class using the = sign:
           A a1;
           A a2 = a1; // assignment operator called
        c. the third one is when you pass a parameter to a function and you pass it by value:
************************
The point is that the copy constructor is used when you declare a new object and initialize it with another object, this in

A A1; // No copy constructor used.  Default constructor used.  
A A2(A1); // Copy constructor used to make A2 a copy of A1;
A A3 = A2; // Copy constructor called to make A3 a copy of A2.  
                   // Note that operator = is NOT called in this case.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
I recomend that you check out the Scott Meyers Books "Effective C++" and "More Effective C++"  They are written for intermediate C++ programmers who are beginning to ask these sorts of questions.  They each focus on about 20 issues, like this, that are often problems for C++ programers.  Every C++ programmer needs a copy,
0
 

Expert Comment

by:koskia
Comment Utility
just a little mistake
ofcourse:
A A1;
A A3 = A1; // calls a copy constructor and not assignment

type mistake, thanks for noticing
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
Well the strange part is that you had if for the case

A a2(a1); // assignment operator called

Which obviously is not the assignment operator.  Many people mistakenly believe that the = in an initialization will invoke the assignment operator, but I've never seen the reverse.  So I figured it was a "typo".
0
 

Expert Comment

by:koskia
Comment Utility
believe me nietod, I know the material, just a typing mistake
:-), that's why all you other experts are out there.


0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
Diana, in one sentence:
A copy ctor is the member function that creates copies of an object.  Everything else is details (important details but still details).

Copy ctors are invoked whenever an object is passed (by value) or returned from a function.

Now go back and read kosika's answer...

Oh, one more thing, the usual declaration of a copy ctor is T(const T&).
0
 

Expert Comment

by:koskia
Comment Utility
caught me again,
this time alexo.

I've written it all down, but got a really bad effect on the details.

ofcourse A(const A& a1);
and not without the const
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 11

Expert Comment

by:alexo
Comment Utility
>> caught me again
You're probably still digesting the fact that Pnina Rosenblum decided to run for PM...
0
 

Author Comment

by:Diana_pal
Comment Utility
I am just looking into your answer....
0
 

Author Comment

by:Diana_pal
Comment Utility
I am just looking into your answer....
0
 

Author Comment

by:Diana_pal
Comment Utility
Hi koskia,

The typos may cause characters fall off the screen or make the
compiler fret and fume. To me it really didn't matter because
your answer provided good reading. It helped me to digest the paradigm. I am grateful to you.

I am also grateful to  nietod and alexo for their hawkish eyes
and suggestions.

I am giving you additional 25 more points right away but pl explain the following code, why the self check is required?

A::operator=(A& other)
{
   if (this == &other)  // checking for self
       return;

    p_num = new int(*other.p_num); // now points to another
                                   //  placein memory
}


I still feel that life would have been simpler without
Constructors and destructors. We did it in the primitive C
and are still doing it, no problems!!

Thanks.


0
 

Author Comment

by:Diana_pal
Comment Utility
Hi koskia,

The typos may cause characters fall off the screen or make the
compiler fret and fume. To me it really didn't matter because
your answer provided good reading. It helped me to digest the paradigm. I am grateful to you.

I am also grateful to  nietod and alexo for their hawkish eyes
and suggestions.

I am giving you additional 25 more points right away but pl explain the following code, why the self check is required?

A::operator=(A& other)
{
   if (this == &other)  // checking for self
       return;

    p_num = new int(*other.p_num); // now points to another
                                   //  placein memory
}


I still feel that life would have been simpler without
Constructors and destructors. We did it in the primitive C
and are still doing it, no problems!!

Thanks.


0
 

Author Comment

by:Diana_pal
Comment Utility
Adjusted points to 75
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
The feature you picked out is very important an is often forgotten resulting in crashes, the code has one little omission that might make this actually clearer  (but might not)  it should read.

A::operator=(A& other)
     {
        if (this == &other)  // checking for self
            return;

         delete p_num;   //// MISSED;
         p_num = new int(*other.p_num); // now points to another
                                        //  placein memory
     }

Now you understand, right?  Well, probably not.  This is important because you could do

A SomeA;

SomeA = SomeA;  // This line will die without that test.

(No programmer would do that on purpose, but in complex code the equivalent statement may occur as part of a complex algorithm)  If you did not have that test the lines

         delete p_num;   //// MISSED;
         p_num = new int(*other.p_num); // now points to another

would be executed.  Remember that in this case other is the same as this.  so when this's p_num is deleted, it is also deleting other's p_num.  So the first line delete's p_num and the next line tries to create a new one using what other.p_num points to.  that will crash because other.p_num is now invalid.  

The test.

if (this == &other)  // checking for self

prevents this.   If the two object are the same, then it just returns.  there is no need to do the logic of the = in that case.


>>  I still feel that life would have been simpler without
>> Constructors and destructors. We did it in the primitive C
>> and are still doing it, no problems!!
In 6 months, you will not be able to explain how you got by without them.  I promise.  
0
 

Expert Comment

by:koskia
Comment Utility
I can't understand how I gave such a bad answer :)
with all this bugs you see in my code, must have been sleeping when writing it.

thanks again nietod for adding the delete line.
you write this code so much, and so casually, and when you gives someone else an answer you forget everything.

but, I hope you read nietod's answer, it should sefice.

you must check assignment to self, because of the problem accesing a deleted pointer, nietod says it all.

thanks for the points,
see you ALL again, in here.

asaf
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
>> I can't understand how I gave such a bad answer :)
Well, the longer the answer--the more changce for bugs.  You covered about every aspect of the copy constuctor I can think of and then even branched into related topics.  Bound to be an error or to.  It still a good answer.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now