标签:c++ 深拷贝
在学习自己实现string类的时候老师讲解过深拷贝和浅拷贝,最近学习STL又遇到了这个问题,发现自己之前的理解不甚深刻,就写了这篇文章来和大家分享自己的再次理解,希望有所收获。
浅拷贝(位拷贝):指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。
举一个我们在C++中常常遇到例子,即在定义一个类A,使用类似A a; A a1(a);或者A a1 = a; 的时候,由于没有自定义拷贝构造函数,C++编译器自动会产生一个默认的拷贝构造函数。这个默认的拷贝构造函数采用的是“位拷贝”(浅拷贝),而非“值拷贝”(深拷贝)的方式,如果类中含有指针变量,默认的拷贝构造函数必定出错。浅拷贝,只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,这样就会引发一系列的问题。
那么,浅拷贝究竟可能引发什么问题呢?
First——>浅拷贝只是拷贝了指针,使得两个指针指向同一个地址,这样当该对象调用结束调用析构函数的时候就会造成同一个内存被释放两次的问题,从而造成程序崩溃;
Second——>浅拷贝使得两个指针指向同一块内存,任何一个进行改动都会影响到另一个;
Third——>释放内存的时候,如果先将a进行释放,再释放a1的时候就会由于a和a1同时指向一块内存,而a已经释放,所以其所指的那块空间也不能再使用了,a1释放时就会无法操作该空间导致内存泄漏。
因此有了深拷贝的方式来防止这些问题的出现。
深拷贝(值拷贝):是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
也就是说深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,使得深拷贝后两个指针指向不同的空间,从而避免浅拷贝引发的一系列问题。
利用深拷贝实现string的拷贝构造函数:
String(const String &other) { int length = strlen(other.m_data); m_data = new char[length + 1]; strcpy(m_data, other.m_data); }
可以看到在拷贝构造函数中为成员变量申请了新的内存空间,这就使得两个对象的成员变量不指向同一个内存空间,程序执行顺利。
而利用默认的拷贝构造函数时就会出现问题,看看下面的代码:
class A { public: A() // 构造函数,p指向堆中分配的一空间 { m_data = new char(100); printf("默认构造函数\n"); } ~A() // 析构函数,释放动态分配的空间 { if(m_data != NULL) { delete m_data; m_data = NULL; printf("析构函数\n"); } } private: char *m_data; // 一指针成员 }; int main() { A a; A b(a); // 复制对象 return 0; }
由于没有拷贝构造函数,走编译器默认的拷贝构造函数,A b(a); 进行对象析构时,会造成释放同一内存空间2次,导致内存泄露。
由此很容易总结出深拷贝和浅拷贝的区别:
浅拷贝是指将对象中的数值类型的字段拷贝到新的对象中,而对象中的引用型字段则指复制它的一个引用到目标对象。如果改变目标对象 中引用型字段的值他将反映在原是对象中,也就是说原始对象中对应的字段也会发生变化。深拷贝与浅拷贝不同的是对于引用的处理,深拷贝将会在新对象中创建一 个新的和原是对象中对应字段相同(内容相同)的字段,也就是说这个引用和原是对象的引用是不同的,我们在改变新对象中的这个字段的时候是不会影响到原始对象中对应字段的内容。本文出自 “七月朔风” 博客,请务必保留此出处http://luminous.blog.51cto.com/10797288/1826351
标签:c++ 深拷贝
原文地址:http://luminous.blog.51cto.com/10797288/1826351