Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

All about copy constructor

Posted on 1999-01-20
17
292 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
ID: 1184671
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
ID: 1184672
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
ID: 1184673
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
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 

Expert Comment

by:koskia
ID: 1184674
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
ID: 1184675
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
ID: 1184676
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
ID: 1184677
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
ID: 1184678
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
 
LVL 11

Expert Comment

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

Author Comment

by:Diana_pal
ID: 1184680
I am just looking into your answer....
0
 

Author Comment

by:Diana_pal
ID: 1184681
I am just looking into your answer....
0
 

Author Comment

by:Diana_pal
ID: 1184682
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
ID: 1184683
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
ID: 1184684
Adjusted points to 75
0
 
LVL 22

Expert Comment

by:nietod
ID: 1184685
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
ID: 1184686
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
ID: 1184687
>> 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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
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 pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

792 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