一:浅拷贝
同一个类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的对象,这种情况被称为浅拷贝。
一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动态内存释放的处理,会导致内存问题。
下面是浅拷贝的例子:
  //构造函数来初始化属性
  class  Student
  {
  public:
	    Student()
	    {
m_Name=NULL;
age=0;
	    }
	    Student(char  *name,int  age)
	    {
		      m_Name=(char *)malloc(strlen(name)+1);   //堆区的空间
		      strcpy(m_Name,age);
		      this->age=age;
	    }
	    ~Student()
	    {
		      cout<<"析构函数调用\n";
		      if(m_Name!=NULL)
		      {
			        free(m_Name);
			        m_Name=NULL;    //防止出现野指针
		      }
	    }	
	    char  *m_Name;
	    int  age;
  };
  void   test01()
  {
	    Student   stu1("tong",10);         //调用有参构造函数
	    Student        stu2(stu1);        //调用拷贝构造
}
int main()
{
test01();
return 0;
}
注意:上面的程序运行的话会崩掉。
解析:由于上面的类没有提供拷贝构造函数, 系统会提供默认的拷贝构造函数,这种情况下是简单的拷贝;由于是简单的拷贝,会使stu2对象中m_Name和stu1对象中m_Name指向相同的内存空间,当stu1执行到析构函数时,指向的内存(0x0001)就会被释放(free),这时候stu2指向的这块空间就不存在了,那会stu2的析构执行时就会出错(程序也会崩掉)。下面是stu1和stu2的图解:
  
二:深拷贝
由于系统默认提供的拷贝构造函数只是简单的赋值,如果属性里有指向堆区的数据,那么浅拷贝会导致重复释放内存的异常问题。
那么这时候就要用到深拷贝,也就是自己为类提供个拷贝构造函数,为属性的成员(指针)另外开辟个独立堆区空间,这样的就叫做深拷贝。
代码的更改如下:
  class Student
  {
  public:
    Student()
    {
m_Name=NULL;
age=0;
    }
    Student(char *name,int age)
    {
      m_Name=(char *)malloc(strlen(name)+1); //堆区的空间
      strcpy(m_Name,age);
      this->age=age;
    }
Student(const Student &p)
{
age=p.age;
m_Name=(char *)malloc(strlen(p.m_Name)+1);
strcpy(m_Name,p.m_Name);
}
    ~Student()
    {
      cout<<"析构函数调用\n";
      if(m_Name!=NULL)
      {
        free(m_Name);
        m_Name=NULL; //防止出现野指针
      }
    }
    char *m_Name;
    int age;
  };
  void test01()
  {
    Student   stu1("tong",10); //调用有参构造函数
    Student        stu2(stu1); //调用拷贝构造
}
int main()
{
test01();
return 0;
}
注:这样的话,代码的运行就不会出现崩溃的问题了。
原文:https://www.cnblogs.com/Unclebigdata/p/14387380.html