C++中的浅拷贝与深拷贝

类中的数据在有指针的情况下,浅拷贝只是增加了一个指针,指向已经存在的内存,而深拷贝就是新增加一个指针并指向新申请的一块内存,使这个新增加的指针指向新开辟的内存,深拷贝可以有效避免,浅拷贝重复释放同一内存的错误,现举例说明如下:


#include <iostream>
using namespace std;

class Student
{
         private:
               int num;
               char *name;
         public:
                Student();
                ~Student();
};

Student::Student()
{
       name = new char(10);
       cout << "Student" << endl;

}
Student::~Student()
{
        cout << "~Student " << endl;
        delete name;
        name = NULL;
}


int main()
{
         Student s1;
         Student s2(s1);//用对象s1初始化s2

         return 0;
}

执行之后:

Student
~Student
~student
press any key to continue

 可以看出,调用了一次构造函数,执行了两个析构函数(两个对象的指针成员指向的内存相同,可以添加打印地址验证),这就造成了name指针被分配了一次内存,却被释放了两次,这样会造成严重的内存泄露问题,究其原因是因为,当类中函数指针数据成员时候,用一个对象初始另外一个对象时候会自动调用默认的拷贝构造函数,即此时进行的时浅拷贝,而由于含有指针成员,所有拷贝后,新生成的指针也指向test1中所分配的内存,这就造成的同一块内存有两个指针指向它,对其进行了两次释放,早过就造成了严重的内存泄露的问题。

所以,对于这种情况,显然是应该使用深拷贝,即自己实现拷贝函数,而不使用默认的,代码如下:

Student::Student(const Student &s)
{
         name = new char(10);
         memcpy(name, s.name, strlen(s.name));
}

总结:浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针(自己实现)。

当对象中存在指针成员时,除了在复制对象时需要考虑自定义拷贝构造函数,还应该考虑以下两种情形:

1.当函数的参数为对象时,实参传递给形参的实际上是实参的一个拷贝对象,系统自动通过拷贝构造函数实现;

2.当函数的返回值为一个对象时,该对象实际上是函数内对象的一个拷贝,用于返回函数调用处。

如何避免两次delete同一块内存

正确的做法:

   int* p=new int(1);
   delete p;
   p = NULL;
 

扫描二维码关注公众号,回复: 6624800 查看本文章

以下结论可以有助于你理解

(1)delete 一次以后,p成了野指针,它作为地址的值还是有效地没还可以访问它以前指向的内存,不过那片内存被重新格式化了(不是真正的格式化,意思是可以重新被分配);
(2)p不等于NULL,用 if(p) 语句不能判断它指向的内存是否有效(此时它指向的内存无效,p本身有效);
(3)delete 一次以后,不能再次delete,否则会报错;
(4)此时如果误用p指针,仍然可以修改内存的值和从该处取出数值,但此时数据不受保护,该内存空间可能被重新被分配给别的变量;
(5)如果p指向的空间再次被new函数分配,即使是分配给别的指针,即使分配大小与原来不一样,p又恢复了效力,可以改变内存的值,甚至可以重新被delete,p的作用与新分配的指针一样;

(6)删除为空(NULL)的指针是不会有任何问题的吗?确实是如此。

猜你喜欢

转载自blog.csdn.net/shanshenyuyou/article/details/93709853