Diiference between copy constructor and overloading = operator


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Page 1 of 2 12 LastLast
Results 1 to 15 of 18

Thread: Diiference between copy constructor and overloading = operator

  1. #1
    Join Date
    Jul 2009
    Location
    Bangalore
    Posts
    23

    Diiference between copy constructor and overloading = operator

    Hi,
    I am currently writing a matix calculations program where we have to implement =operator overloading and copy constructor.But I could see that the program is giving wrong output bcos there occured a confusion in copy constructor and =operator overloading.I would like to know whether we can implement both copy constructor and =operator overloading in a program.
    Thanks and regards,
    Anjana
    Attached Files Attached Files

  2. #2
    Join Date
    Nov 2003
    Posts
    4,118
    the general rule is that a copy constructor is called when you initialize a new object with an existing object, regardless of whether the initialization uses the = notation or the () notation. Similarly, whenever you assign to an existing object, the assignment operator is called, never the copy ctor.
    I haven't tested your program. Can you tell which results are wrong?
    Danny Kalev

  3. #3
    Join Date
    Jul 2009
    Location
    Bangalore
    Posts
    23
    I have taken 2 matrices a and b and the result after addition is saved in matrix d.After the result is saved in d,I could find that matrix a and b values also has been changed to the resultant matrix.When I debugged,I could see that after +operator is called for addition,copy constructor is also executed.I am not able to get this logic as why copy constructor is called soon after addition.

  4. #4
    Join Date
    Dec 2003
    Posts
    3,366
    Your array is made of pointers, inside the class.

    Your assignment moves these pointers:
    array = whatever.array; ///now, THIS and THAT are pointing to the same memory location, so if you modify THIS, THAT changes, if you modify THAT, THIS changes. Not good!!


    You absolutely MUST make copies of the data at some point, not just swap pointers. There will be times in your code where swapping pointers is faster but most of your assignments need to be raw data copys instead.

    Let me suggest:

    Matrix& operator=(Matrix obj)
    {
    // ALLOCATE MEMORY FOR THIS TO ENSURE IT IS BIG ENOUGH FOR OBJ
    //DONT FORGET TO FREE EXISTING MEMORY

    rows=obj.rows;
    cols=obj.cols;
    //array=obj.array; pointer chaos removed
    for(int r = 0; r < rows; r++)
    for(int c = 0; c < cols; c++)
    array[r][c] = obj.array[r][c];
    return *this;
    }

  5. #5
    Join Date
    Dec 2003
    Posts
    3,366
    Now, I don't know what this is for, but you are very likely making your life harder than it needs to be with double pointers and excessive data movement. If you need to make this stuff faster, let me know. Faster or not, I cannot recommed enough using a single dimensional pointer for array to reduce some of the excessive looping.

    double * array = new double[rows*cols];
    //arrray [5][6] can be reached with:
    array[5*cols+6]; //you get used to it.

    Now, something like add becomes:

    for(int i = 0; i < rows*cols; i++)
    result[i] = a[i] + b[i]; //an entire for loop eliminated.

    On top of this, imagine you want to assign a 3X5 the result of something that is a 5X2. It will fit into the data, you need to put 10 numbers into 15 locations so thats fine. BUT, using your method, you cannot because you have too few rows in the destination, you must reallocate your memory. If you go my way, you can re-use the memory (check, yes its big enough, move along). Also, you can do things like transpose in place without reallocations, etc.

    Just a quick thought.

  6. #6
    Join Date
    Jul 2009
    Location
    Bangalore
    Posts
    23
    From the below explanation what I understood is :
    Matrix d(a) and Matrix b(a) is pointing to the same memory location.So what ever changes made by matrix d,it is reflected in matrix a and b.Please correct me if I am wrong.
    The reason why I am using double pointers is I was given the below assignment by my mentor.
    Implement addition and multiplication operation
    row and col of matrix is dynamic. So it should not be hard coded
    Implement copy constructor and copy assignment operator
    Implement post and pre increment / decrement operators to increment / decrement each elements in the matrix
    Overload the ostream << operator
    Private members will be as follows
    o Int rows;
    o Int cols;
    o Int **array;
    As far as I know I have implemented everything but the confusion in copy constructor and =operator overloading gives a different o/p,if we add the matrices for the second time.
    I have tried to give the declarations as
    Matrix d=a;
    so that both dont point to same memory location.but the o/p is still the same.I have also given the =operator overloading definition as suggested.For all the cases,the addition result is correct for the first time,but soon after that matrix a and b copies the resultant matrix.

  7. #7
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    some of the answers you need are actually here:
    http://forums.devx.com/showthread.php?t=172448
    There are better threads to explain the issue but this is so recent....

    The main point is:
    If you declare and intitialise an object like this
    Code:
    Matrix obj1;
    Matrix obj2 = obj1; // declare and initialise obj2
    Matrix obj3(obj1); // declare and initialise obj3
    that is *NOT* done using the assignment operator, but the copy constructor.
    Both obj2 and obj3 are being initialised using the copy-constructor.
    Once your objects are declared and you assign one the othe, then the assignment operator is used
    Code:
    Matrix obj1;
    Matrix obj2 = obj1; // declare and initialise obj2
    Matrix obj3(obj1); // declare and initialise obj3
    
    obj1 = obj3; // here the assignment operator is used
    We could further confuse you by telling you what happens if you have implicit conversions in your class, but you better get you head around this...
    Last edited by drkybelk; 07-03-2009 at 05:13 AM.
    DKyb
    -------------------------------
    Life is a short warm moment -
    Death is the long cold rest.
    Pink Floyd
    -------------------------------

  8. #8
    Join Date
    Dec 2003
    Posts
    3,366
    Quote Originally Posted by anjana View Post
    From the below explanation what I understood is :
    Matrix d(a) and Matrix b(a) is pointing to the same memory location.So what ever changes made by matrix d,it is reflected in matrix a and b.Please correct me if I am wrong.
    The reason why I am using double pointers is I was given the below assignment by my mentor.
    Implement addition and multiplication operation
    row and col of matrix is dynamic. So it should not be hard coded
    Implement copy constructor and copy assignment operator
    Implement post and pre increment / decrement operators to increment / decrement each elements in the matrix
    Overload the ostream << operator
    Private members will be as follows
    o Int rows;
    o Int cols;
    o Int **array;
    As far as I know I have implemented everything but the confusion in copy constructor and =operator overloading gives a different o/p,if we add the matrices for the second time.
    I have tried to give the declarations as
    Matrix d=a;
    so that both dont point to same memory location.but the o/p is still the same.I have also given the =operator overloading definition as suggested.For all the cases,the addition result is correct for the first time,but soon after that matrix a and b copies the resultant matrix.
    Well if the assignment demands ** then you use **, but I would tell him its a bad idea =)

    Not sure what you are still doing, but the reason they are the same data is because of pointer goofs, it has to be. You have to be very precise and ensure that every class has a pointer that it creates and maintains and that pointer must *never* be assigned another pointer that is the data of another class (for now, later, you can set it up to allow this if you have a need, but for now consider that to be an error). You must only assign data and not pointers, if you do this, the problem should clear up.

    Very simply:

    if your copy CTOR has
    array = incoming.array;
    its wrong.

    if your operater = has
    array = incoming.array;
    its wrong.

    If any other function has
    array = another_object.array;
    its wrong.

    These must all be loops, and with **, they must be double loops. To be 100% precise, this is what is required:

    if ((row != incoming.rows) || (cols != incoming.cols)
    for(i = 0; i < rows; i++)
    delete[] array[i]; ///deletes all the column pointers
    delete[] array; ///delets the row pointer

    array = new int*[incoming.rows];
    for(i = 0; i < incoming.rows, i++)
    array[i] = new int[incoming.cols];
    rows = incoming.rows;
    cols = incoming.cols;
    for(r = 0; r< rows; r++)
    for(c = 0; c<cols; c++)
    array[r][c] = incoming.array[r][c];

    to replace every single instance of array = incoming.array, you need *all that* stuff.

    Otherwise, you are at risk for memory errors and problems.

  9. #9
    Join Date
    Jul 2009
    Location
    Bangalore
    Posts
    23
    After reading all the comments,I understood the pointer **array was causing all the problems.So I simply declared array as normal array,ie,int array[10][10];
    And it solved the problem.I hope I can put the pointer declaration as a limitation.:).
    i couldnt find another way to solve it.
    Attached Files Attached Files

  10. #10
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    Part of your assignment is to make row and col sizes dynamic. 'fraid you can't do that with arrays.... Your instructor specifically wanted you to think about neccessary memory management - a key skill when programming in C++. I guess you'll have to try to make it work with double pointers. He gave you valuable hints though. Whenever you have pointer - member - variables you should create the four standard methods: def con, copy con, asgnmt and destr (which you did, I believe). You need to pay attention, though as to what those are supposed to do and what they actually do. ;-) This will become second nature soon enough and you will save yourself a lot of grief if you learn it now properly, believe me!
    DKyb
    -------------------------------
    Life is a short warm moment -
    Death is the long cold rest.
    Pink Floyd
    -------------------------------

  11. #11
    Join Date
    Jul 2009
    Location
    Bangalore
    Posts
    23
    I am willing to learn more on this.Could anyone please give an example program where a double pointer class varaible can be accessed effectively using copy constructor ?
    Thanks in advance,
    Anjana

  12. #12
    Join Date
    Dec 2007
    Posts
    401
    Code:
    #include <cassert>
    
    struct matrix
    {
        matrix( int rows, int cols ) ;
        ~matrix() ;
        matrix( const matrix& that ) ;
        matrix& operator= ( const matrix& that ) ;
    
        // other matrix operations
        // friend std::ostream& operator<< ( std::ostream&, const matrix& ) ;
    
        private:
          int rows ;
          int cols ;
          int** array ;
    
          void allocate() ;
          void deallocate() ;
          void zero() ;
          void copy_data( const matrix& that ) ;
    };
    
    void matrix::allocate()
    {
       assert( ( rows > 0 ) && ( cols > 0 ) ) ;
       array = new int* [rows] ;
       array[0] = new int [rows*cols] ;
       for( int i=1 ; i<rows ; ++i ) array[i] = array[i-1] + cols ;
    }
    
    void matrix::deallocate()
    {
      delete [] array[0] ;
      delete [] array ;
    }
    
    void matrix::zero()
    {
       for( int r = 0 ; r < rows ; ++r )
          for( int c = 0 ; c < cols ; ++c ) array[r][c] = 0 ;
    }
    
    void matrix::copy_data( const matrix& that )
    {
       assert( ( rows == that.rows ) && ( cols == that.cols ) ) ;
       for( int r = 0 ; r < rows ; ++r )
          for( int c = 0 ; c < cols ; ++c )
              array[r][c] = that.array[r][c] ;
    }
    
    matrix::matrix( int r, int c ) : rows(r), cols(c)
    {
       allocate() ;
       zero() ;
    }
    
    matrix::~matrix() { deallocate() ; }
    
    matrix::matrix( const matrix& that ) : rows(that.rows), cols(that.cols)
    {
       allocate() ;
       copy_data(that) ;
    }
    
    matrix& matrix::operator= ( const matrix& that )
    {
        if( this != &that ) // not a self-assignment
        {
          deallocate() ;
    
          rows = that.rows ;
          cols = that.cols ;
    
          allocate() ;
          copy_data(that) ;
        }
        return *this ;
    }

  13. #13
    Join Date
    Dec 2003
    Posts
    3,366
    If you go there, let me at least suggest tracking (in a private variable in the class) the true rows and cols of the matrix (how large the allocated memory is currently, this is being done currently) and let the public rows and cols (not currently present) be anything smaller than the true ones (and, if the public ones are not directly settable by the user, the math functions at least should change them and any copy operations should be able to change them).

    For example, if you had allocated matrix M as a 10 X 10, and the result of your multiply is a 4 X 7, allow it to be copied/assigned into M (instead of the hard == comparision on rows, cols, use <= or < depending on your logic). The true rows and cols would remain 10 X 10 and the public ones would be 4 X 7. This saves a pointless re-allocation (destroy 10X10 and create a 4X7) upon size change when the memory was plenty big enough. Keeping the size of the memory allocated seperate from the mathematical concept of dimensions will help a lot in many ways -- there are iterative/recursive routines that lop off a row or column until its a 2X2 or 3X3 and then pop back out, for example. It also allows you to allocate the memory to the largest possible size in your system, so you never need to re-allocate a matrix (if you want to use the time/space tradeoff of wasted space to prevent reallocations --it opens the door to *do* that or not as a choice).

  14. #14
    Join Date
    Aug 2009
    Posts
    6
    if you use = you will get a unnessesary call to the base constructor, but with () you can get a slight performance bonus,as the VTBL already has the possible types figured out.

  15. #15
    Join Date
    Dec 2007
    Posts
    401
    if you use = you will get a unnessesary call to the base constructor, but with () you can get a slight performance bonus
    if an object is initialized with an other object of exactly the same type (using a copy constructor), both forms of the initializer will generate identical code.
    Code:
    object_type new_object = existing_object ;
    object_type new_object( existing_object ) ;
    Code:
    struct A
    {
        static int n ;
        virtual int foo() const { return ++n ; }
    } ;
    int A::n = 0 ;
    
    struct B : A
    {
        static int n ;
        virtual int foo() const { return --n ; }
    } ;
    
    void foo( A existing_object )
    {
        A new_object( existing_object ) ;
    }
    
    void bar( A existing_object )
    {
        A new_object = existing_object ;
    }
    extract of assembly listing generated by
    g++ -c -g -Wa,-a,-ad -fomit-frame-pointer -Wall -werror -std=c++98 init.cc > init.asm

    Code:
    15:temp.cc       **** void foo( A existing_object )
    16:temp.cc       **** {
          53              		.loc 1 16 0
          54 0000 83EC2C   		subl	$44, %esp
          55              	.LCFI0:
          56              	.LBB3:
    17:temp.cc       ****   A new_object( existing_object ) ;
          57              		.loc 1 17 0
          58 0003 8B442430 		movl	48(%esp), %eax
          59 0007 89442404 		movl	%eax, 4(%esp)
          60 000b 8D44241C 		leal	28(%esp), %eax
          61 000f 890424   		movl	%eax, (%esp)
          62 0012 E8FCFFFF 		call	_ZN1AC1ERKS_
          62      FF
          63              	.LBE3:
    18:temp.cc       **** }
          64              		.loc 1 18 0
          65 0017 83C42C   		addl	$44, %esp
          66 001a C3       		ret
    
    19:temp.cc       **** 
    20:temp.cc       **** void bar( A existing_object )
    21:temp.cc       **** {
          73              		.loc 1 21 0
          74 001b 83EC2C   		subl	$44, %esp
          75              	.LCFI1:
          76              	.LBB4:
    22:temp.cc       ****   A new_object = existing_object ;
          77              		.loc 1 22 0
          78 001e 8B442430 		movl	48(%esp), %eax
          79 0022 89442404 		movl	%eax, 4(%esp)
          80 0026 8D44241C 		leal	28(%esp), %eax
          81 002a 890424   		movl	%eax, (%esp)
          82 002d E8FCFFFF 		call	_ZN1AC1ERKS_
          82      FF
          83              	.LBE4:
    23:temp.cc       **** }
          84              		.loc 1 23 0
          85 0032 83C42C   		addl	$44, %esp
          86 0035 C3       		ret

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center