c++浅拷贝和深拷贝

同类对象之间可以通过赋值运算符 = 互相赋值。如果没有经过重载, = 的作用就是将赋值号左侧对象的值一一赋值给左侧对象,这相当于值的拷贝,称作"浅拷贝"。如果赋值对象中涉及指针或引用,则它们之间是相互关联的,一个值变化了,另一个值也跟着变化。因为对象中的指针指向的是同一个内存地址。

重载赋值运算符后,赋值语句的功能是将一个对象中指针成员变量指向的内容复制到另一个对象中指针成员变量指向的地方,这样的拷贝称作”深拷贝“。

浅拷贝示例

#include <iostream>
using namespace std;

class Pointer
{
public:
	int a;
	int* p;
	Pointer() {
		a = 100;
		p = new int(10);
	}
	Pointer(const Pointer& temp) {
		if (this != &temp) {
			a = temp.a;
			p = temp.p; // 浅拷贝
		}
	}
	~Pointer() {
		// 当对象p1消亡时,需要释放构造函数中动态申请的空间,也就是那个整型值占据的空间,
		// 当对象p2消亡时,也会试图释放这个空间,重复释放同一块空间会产生错误
		//if (p != NULL) delete p; 
		cout << "析构" << endl;
	}
};
int main()
{
	Pointer p1;
	Pointer p2(p1);//使用复制构造函数
	Pointer p3 = p1;//使用复制构造函数
	cout << "\n初始化后,各对象的值及内存地址" << endl;
	cout << "对象名\t 对象地址    a的值    p中的值    p指向的值    p的地址" << endl;
	cout << "p1:\t" << &p1 << ",\t" << p1.a << ",\t" << p1.p << ",\t" << *p1.p << ",\t" << &p1.p << endl;
	cout << "p2:\t" << &p2 << ",\t" << p2.a << ",\t" << p2.p << ",\t" << *p2.p << ",\t" << &p2.p << endl;
	cout << "p3:\t" << &p3 << ",\t" << p3.a << ",\t" << p3.p << ",\t" << *p3.p << ",\t" << &p3.p << endl;

	*p1.p = 20;
	p2.a = 300;
	cout << "\n修改后,各对象的值及内存地址" << endl;
	cout << "对象名\t 对象地址    a的值    p中的值    p指向的值    p的地址" << endl;
	cout << "p1:\t" << &p1 << ",\t" << p1.a << ",\t" << p1.p << ",\t" << *p1.p << ",\t" << &p1.p << endl;
	cout << "p2:\t" << &p2 << ",\t" << p2.a << ",\t" << p2.p << ",\t" << *p2.p << ",\t" << &p2.p << endl;
	cout << "p3:\t" << &p3 << ",\t" << p3.a << ",\t" << p3.p << ",\t" << *p3.p << ",\t" << &p3.p << endl;

	return 0;
}

结果

初始化后,各对象的值及内存地址
对象名   对象地址    a的值    p中的值    p指向的值    p的地址
p1:     007FFDC4,       100,    00CF5FE0,       10,     007FFDC8
p2:     007FFDB4,       100,    00CF5FE0,       10,     007FFDB8
p3:     007FFDA4,       100,    00CF5FE0,       10,     007FFDA8

修改后,各对象的值及内存地址
对象名   对象地址    a的值    p中的值    p指向的值    p的地址
p1:     007FFDC4,       100,    00CF5FE0,       20,     007FFDC8
p2:     007FFDB4,       300,    00CF5FE0,       20,     007FFDB8
p3:     007FFDA4,       100,    00CF5FE0,       20,     007FFDA8
析构
析构
析构

 分析

分析:

当对象p1消亡时,需要释放构造函数中动态申请的空间,也就是那个整型值占据的空间,二当对象p2消亡时,也会试图释放这个空间,重复释放同一块空间会产生错误。

当使用

Pointer p4;
p4 = p1;

则对象p4中成员变量p原来指向的空间被忽略了,创建对象p4时,构造函数已经为p4中的成员变量分配了空间,并赋予了初值10。语句p4 = p1,将p1中成员变量的值分别赋值给p4的各成员变量,p4中成员变量p指向了p1中p指针指向的地址,而丢失了原来指向的地址,如果没有其他的指针指向这个地址,则这块内存永远不会被释放,成为垃圾内存。

深拷贝示例

#include <iostream>
using namespace std;

class Pointer
{
public:
	int a;
	int* p;
	Pointer() {
		a = 100;
		p = new int(10);
	}
	Pointer(const Pointer& temp) {
		if (this != &temp) {
			a = temp.a;
			p = new int(); 
			*p = *temp.p; // 深拷贝
		}
	}
	~Pointer() {
		if (p != NULL) delete p;
	}

	Pointer& operator=(const Pointer& c) {
		if (this == &c) return *this; // 避免a=a这样的赋值
		delete this->p; // 释放原来的空间
		this->p = new int(*c.p);//申请新的空间
		return *this;
	}
};
int main()
{
	Pointer p1;
	Pointer p2(p1);//使用复制构造函数
	Pointer p3;
	p1 = p1; //测试赋值运算符重载
	p3 = p1; //使用复制构造函数
	cout << "\n初始化后,各对象的值及内存地址" << endl;
	cout << "对象名\t 对象地址    a的值    p中的值    p指向的值    p的地址" << endl;
	cout << "p1:\t" << &p1 << ",\t" << p1.a << ",\t" << p1.p << ",\t" << *p1.p << ",\t" << &p1.p << endl;
	cout << "p2:\t" << &p2 << ",\t" << p2.a << ",\t" << p2.p << ",\t" << *p2.p << ",\t" << &p2.p << endl;
	cout << "p3:\t" << &p3 << ",\t" << p3.a << ",\t" << p3.p << ",\t" << *p3.p << ",\t" << &p3.p << endl;

	*p1.p = 20;
	p2.a = 300;
	cout << "\n修改后,各对象的值及内存地址" << endl;
	cout << "对象名\t 对象地址    a的值    p中的值    p指向的值    p的地址" << endl;
	cout << "p1:\t" << &p1 << ",\t" << p1.a << ",\t" << p1.p << ",\t" << *p1.p << ",\t" << &p1.p << endl;
	cout << "p2:\t" << &p2 << ",\t" << p2.a << ",\t" << p2.p << ",\t" << *p2.p << ",\t" << &p2.p << endl;
	cout << "p3:\t" << &p3 << ",\t" << p3.a << ",\t" << p3.p << ",\t" << *p3.p << ",\t" << &p3.p << endl;

	return 0;
};

 结果

初始化后,各对象的值及内存地址
对象名   对象地址    a的值    p中的值    p指向的值    p的地址
p1:     0097FBA0,       100,    00E1FA50,       10,     0097FBA4
p2:     0097FB90,       100,    00E1FA80,       10,     0097FB94
p3:     0097FB80,       100,    00E15F50,       10,     0097FB84

修改后,各对象的值及内存地址
对象名   对象地址    a的值    p中的值    p指向的值    p的地址
p1:     0097FBA0,       100,    00E1FA50,       20,     0097FBA4
p2:     0097FB90,       300,    00E1FA80,       10,     0097FB94
p3:     0097FB80,       100,    00E15F50,       10,     0097FB84

分析

复制构造函数中,原来是进行的浅拷贝,所以整数值及指针值都被复制过来,两个对象中指针成员变量的值相同,也就是都指向同一个位置。新的复制构造函数中,新申请了一个保存整数值的空间,两个对象中指针不再是相同的,也就是说,它们分别指向各自的单元,仅有单元中的值是相同的。析构函数中,因为各对象中指针指向的位置是不同的,所以释放时也不会出现问题。

当执行语句p3 = p1时,使用p1的值初始化p3,函数中,释放掉指针原来执行的空间,再重新申请新的空间,这样可以保证不会与参数对象中指针指向的空间相同。然后使用值*c.p初始化新申请的空间。

来自《c++程序涉及》

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值