形象地聊聊C++中的浅拷贝与深拷贝

         先来看一个简单的程序:

 

#include <iostream>
using namespace std;

class Point
{
public:
	int x;
	int y;

	Point(int xx, int yy)
	{
		x = xx;
		y = yy;
	}
};

int main()
{
	Point A(1, 2);
	Point B(A); // 执行了编译器默认的浅拷贝
	cout << B.x << endl; // 1
	cout << B.y << endl; // 2

	return 0;
}

      

 

       好, 继续看:

 

#include <iostream>
using namespace std;

class Point
{
public:
	int x;
	int y;

	int* pTest;

	Point(int xx, int yy, int* p)
	{
		x = xx;
		y = yy;
		pTest = p;
	}
};

int main()
{
	int m = 0;
	cout << &m  << endl;     // 0013FF7C

	Point A(1, 2, &m);
	cout << A.x << endl;     // 1
	cout << A.y << endl;     // 2
	cout << A.pTest << endl; // 0013FF7C


	Point B(A);              // 执行了编译器默认的浅拷贝
	cout << B.x << endl;     // 1
	cout << B.y << endl;     // 2
	cout << B.pTest << endl; // 0013FF7C

	return 0;
}

      由此可见, 浅拷贝就是浅浅的傻傻的拷贝。 上面这个程序会引出一个问题: 如果A.pTest指向了某一个堆, 那么B.pTest也指向了同一地方。 我们来看看:

 

 

#include <iostream>
using namespace std;

class Point
{
public:
	int x;
	int y;

	int* pTest;

	Point(int xx, int yy)
	{
		x = xx;
		y = yy;
		pTest = new int(100);
	}
};

int main()
{
	Point A(1, 2);
	cout << A.x << endl;      // 1
	cout << A.y << endl;      // 2
	cout << A.pTest << endl;  // 00032738
	cout << *A.pTest << endl; // 100

	Point B(A);               // 执行了编译器默认的浅拷贝
	cout << B.x << endl;      // 1
	cout << B.y << endl;      // 2
	cout << B.pTest << endl;  // 00032738
	cout << *B.pTest << endl; // 100

	return 0;
}

      显然, 如果析构, 则会有两次释放同一堆空间, 危险!!!看看这个危险的代码:

 

 

#include <iostream>
using namespace std;

class Point
{
public:
	int x;
	int y;

	int* pTest;

	Point(int xx, int yy)
	{
		x = xx;
		y = yy;
		pTest = new int(100);
	}

	~Point()
	{
		delete pTest;
	}
};

int main()
{
	// 代码两次释放同一堆空间, 运行的时候出错

	Point A(1, 2);
	cout << A.x << endl;      // 1
	cout << A.y << endl;      // 2
	cout << A.pTest << endl;  // 00032738
	cout << *A.pTest << endl; // 100

	Point B(A);               // 执行了编译器默认的浅拷贝
	cout << B.x << endl;      // 1
	cout << B.y << endl;      // 2
	cout << B.pTest << endl;  // 00032738
	cout << *B.pTest << endl; // 100

	return 0;
}

      上面的代码不仅错误, 而且从逻辑上吧对象A和B无形地建立了关联, 显然是不合理的。

 

 

       看来, 编译器默认的拷贝构造函数是太肤浅了, 编译器不可能做那么多东西, 从逻辑上来讲,也无法做。 是该搞点深的了, 来看程序员自己需要写的深拷贝:

 

#include <iostream>
using namespace std;

class Point
{
public:
	int x;
	int y;

	int* pTest;

	Point(int xx, int yy)
	{
		x = xx;
		y = yy;
		pTest = new int(100);
	}

	~Point()
	{
		delete pTest;
	}

	Point(Point& P)  // 不能是Point(Point P)
	{
		x = P.x;
		y = P.y;
		int value = *P.pTest;
		pTest = new int(value);
	}
};

int main()
{
	Point A(1, 2);
	cout << A.x << endl;      // 1
	cout << A.y << endl;      // 2
	cout << A.pTest << endl;  // 00032738
	cout << *A.pTest << endl; // 100

	Point B(A);               // 执行了程序员自己写的深拷贝
	cout << B.x << endl;      // 1
	cout << B.y << endl;      // 2
	cout << B.pTest << endl;  // 00030930
	cout << *B.pTest << endl; // 100

	return 0;
}

      这就是深拷贝, 依靠程序员自己的实现, 撇清A对象和B对象的关系。

 

 

      来个形象的总结吧: 

      浅拷贝: 丈夫有100元, 取了个没有钱的妻子后, 自己与妻子共同掌管这100元, 花着花着, 有可能吵架呢偷笑
      深拷贝: 丈夫有100元, 取了个有100块钱的妻子后, 自己有100, 妻子有100,  各花各的, 互不干扰, 没有什么争吵大笑

 


 

 

      

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值