Shallow copy of C++ error

  • 2020-05-10 18:35:53
  • OfStack

The shallow copy problem was mentioned in the previous article, that is, when copying an object, it only makes a simple assignment to the data members in the object, and the default copy constructor also performs a shallow copy. If there are dynamic members in an object, such as Pointers, it is not enough to just make a shallow copy, and it is easy to cause errors. The classic example is:


#include <iostream>
#include <stdio.h> 

using namespace std;

class A{
  public:
    A(){m_p = new int(10);};
    ~A(){cout << "destruction function" << endl;delete m_p;}; 
    int* m_p; 
};

void copyTest(A atmp){
  ;
}

int main(){
  A a;
  copyTest(a);
}

This code crashes because delete m_p in the destructor is executed twice, and m_p points to the same block of memory. Because the object a is passed in when copyTest is called, atmp USES a as an argument to perform the default copy constructor, but simply copies the m_p memory address of a to m_p, atmp.m_p only points to the same block of memory as a.m_p.

When copyTest is finished, the temporary variable atmp is destroyed, at which point the destructor is called and delete contains the memory pointed to by m_p. When the main function is finished executing, the a object also needs to be destroyed. At this point, the destructor is executed again. At this point, m_p does not know where to point anymore, and the delete operation causes the program to crash.

There are many ways to solve this problem: one is to implement a smart pointer that counts references to m_p and only executes delete when the reference value is 0; You can also set the initial value of m_p to NULL every time, check whether m_p is NULL before delete operation, and then point m_p to NULL after delete operation. This method is similar to smart pointer in fact, but smart pointer makes more reasonable and effective use of classes for management. Another option is to override the copy constructor to ensure that deep copies are made during object replication, that is, to redistribute memory space and copy the contents of m_p pointing to memory into the allocated space.

This happens only when copying objects using "value passing", which would not happen if we were passing Pointers:


#include <iostream>
#include <stdio.h> 

using namespace std;

class A{
  public:
    A(){m_p = new int(10);};
    ~A(){cout << "destruction function" << endl;delete m_p;}; 
    int* m_p; 
};

void copyTest(A* atmp){
  ;
}

int main(){
  A* a;
  copyTest(a);
}

Since the parameter passed to copyTest is only one address, which refers to the object a, there is no copying of the object, so of course there is no shallow copying problem.


Related articles: