-------------------siwuxie095
深拷贝 与 浅拷贝
对象间的拷贝没那么简单,大致分为两种情况:一种叫做 深拷贝,一种叫做 浅拷贝
看如下实例:定义一个数组类:Array
使用时:
arr1 在实例化时,会调用构造函数,而使用 arr1 初始化 arr2,
arr2 在实例化时,就会调用拷贝构造函数,参数其实就是 arr1
上面的例子比较简单,对其再做稍微地修改:加一个 int 型指针,该指针
在构造函数中从堆中申请了一段内存,且指向了堆中的这段内存,内存的
大小就是 m_iCount,而拷贝构造函数的实现方法还是进行简单的拷贝
使用时:arr1 执行默认构造函数,而 arr1 初始化 arr2 时,就会调用拷贝
构造函数,但这两个例子都只是将数据成员的值进行了简单的拷贝,这种
拷贝模式称为 浅拷贝
但对于第一个例子,使用浅拷贝的方式实现拷贝构造函数并没有任何问题,
而对于第二个例子,肯定是有问题的
经过浅拷贝之后,对象 arr1 中的指针和对象 arr2 中的指针势必会指向同
一块内存,因为在拷贝构造函数中,将 arr1 的 m_pArr 赋值给了 arr2 的
m_pArr,使得这两个变量中存放的是同一个值
此时,如果先给 arr1 的 m_pArr 赋了一些值,再去给 arr2 的 m_pArr
赋值时,这段内存就会被重写,覆盖掉 arr1 的 m_pArr 的值,最严重
的是,当销毁 arr1 对象时,为了避免内存泄露,肯定会释放掉 arr1 中
m_pArr 所指向的这段内存,如果已经释放掉这段内存,再去销毁 arr2
对象时,也会以同样的方式释放掉 arr2 中 m_pArr 所指向的这段内存
相当于同一块内存被释放了两次,这种情况肯定是有问题的,面对这种
问题,计算机会以崩溃的方式向你抗议,提示的错误信息因为晦涩难懂,
不能直奔主题,同样使得初学者感到崩溃 …
所以,希望拷贝构造函数所完成的工作应该是这样的:两个对象的指针
所指向的应该是不同的内存,拷贝时不是将指针的地址简单地拷贝过来,
而是将指针所指向的内存中的每一个元素依次拷贝过来
代码应该写成这样:
两种拷贝方式有着本质的区别,当进行对象拷贝时,不是简单地做值的
拷贝,而是将堆中内存的数据也进行拷贝,这种拷贝模式称为 深拷贝
程序 1:浅拷贝
Array.h:
class Array { public: Array(); Array(int count); Array(const Array &arr); ~Array(); void setCount(int count); int getCount(); void printAddr();//地址查看函数 void printArr(); private: int m_iCount;//数组元素个数 int *m_pArr; }; |
Array.cpp:
#include"Array.h" #include <iostream> using namespace std;
Array::Array() { cout << "Array" << endl; }
Array::Array(int count) { m_iCount = count; m_pArr = new int[m_iCount]; cout << "Array" << endl; }
Array::Array(const Array &arr) { m_pArr = arr.m_pArr; m_iCount = arr.m_iCount; cout << "Array &" << endl; }
Array::~Array() { delete[]m_pArr; m_pArr = NULL; cout << "~Array" << endl; }
void Array::setCount(int count) { m_iCount = count; }
int Array::getCount() { return m_iCount; }
void Array::printAddr() { cout << "m_pArr的值是:" << m_pArr << endl; }
void Array::printArr() { for (int i = 0; i < m_iCount;i++) { cout << m_pArr[i] << " "; } } |
main.cpp:
#include <stdlib.h> #include "Array.h" #include <iostream> using namespace std;
//浅拷贝:将值直接拷贝过去 int main(void) { Array arr1; arr1.setCount(5); Array arr2(arr1); cout << "arr2.m_iCount:" << arr2.getCount() << endl; system("pause"); return 0; } |
运行一览:
程序 2:深拷贝
Array.h:
class Array { public: Array(int count); Array(const Array &arr); ~Array(); void setCount(int count); int getCount(); void printAddr();//地址查看函数 void printArr(); private: int m_iCount;//数组元素个数 int *m_pArr; }; |
Array.cpp:
#include"Array.h" #include <iostream> using namespace std;
Array::Array(int count) { m_iCount = count; m_pArr = new int[m_iCount]; for (int i = 0; i < m_iCount;i++) { m_pArr[i] = i; } cout << "Array" << endl; }
Array::Array(const Array &arr) { m_iCount = arr.m_iCount; m_pArr = new int[m_iCount];//给当前的arr2申请一块新的内存 for (int i = 0; i < m_iCount;i++) { m_pArr[i] = arr.m_pArr[i];//只是将arr1的值拷贝给arr2 } cout << "Array &" << endl; }
//此为浅拷贝: //arr2的指针和arr1的指针指向同一块内存,当给arr1赋值后再给arr2赋值,会覆盖掉arr1的值 //在析构时同一块内存会delete两次 导致错误 //Array::Array(const Array &arr) //{ // m_pArr = arr.m_pArr; // m_iCount = arr.m_iCount; // cout << "Array &" << endl; //}
Array::~Array() { //析构时的内存不同,正常释放 delete[]m_pArr; m_pArr = NULL; cout << "~Array" << endl; }
void Array::setCount(int count) { m_iCount = count; }
int Array::getCount() { return m_iCount; }
void Array::printAddr() { cout << "m_pArr的值是:" << m_pArr << endl; }
void Array::printArr() { for (int i = 0; i < m_iCount; i++) { cout << m_pArr[i] << " "; } cout << endl; } |
main.cpp:
#include <stdlib.h> #include "Array.h" #include <iostream> using namespace std;
//深拷贝:先申请一段内存,再将传入进来的对象的对应 //位置的内存拷贝到申请的内存中去 int main(void) { Array arr1(5); Array arr2(arr1); arr1.printAddr(); arr2.printAddr(); arr1.printArr(); arr2.printArr();
system("pause"); return 0; } |
运行一览:
【made by siwuxie095】