牛客网刷题——深复制与浅复制问题

我们以对象的复制为例,解释深复制与浅复制的概念:
例题from 《C++语言程序设计》郑莉第四版在线教学版
例6_21

#include <iostream>
#include <cassert>
using namespace std;
class Point
{
public:
	Point()
		:x(0),y(0)
	{
		cout << "Default constructor called." << endl;
	}
	Point( int x, int y )
		:x(x),y(y)
	{
		cout << "Constructor called." << endl;
	}
	~Point()
	{
		cout << "Destructor called." << endl; 
	}
	int getX() const
	{
		return x;
	}
	int getY() const
	{
		return y;
	}
	void move( int newX, int newY )
	{
		x = newX;
		y = newY;
	}

private:
	int x;
	int y;
};
class ArrayOfPoints
{
public:
	ArrayOfPoints( int size )
		:size( size )
	{
		points = new Point[ size ];
	}
	//ArrayOfPoints( const ArrayOfPoints &v );//复制构造函数,实现深复制
	~ArrayOfPoints()
	{
		cout << "Deleting" << endl;
		delete [] points;
	}

	Point &element( int index )
	{
		assert( index >= 0 && index < size );
		return points[ index ];
	}
private:
	Point *points;
	int size;
};

//ArrayOfPoints::ArrayOfPoints( const ArrayOfPoints &v )//复制构造函数,实现深复制
//{
//	size = v.size;
//	points = new Point[size];
//	for( int i = 0; i < size; i++ )
//		points[ i ] = v.points[ i ];
//}

int main()
{
	int count;
	cout << "Please enter the count of points:";
	cin >> count;
	ArrayOfPoints pointsArray1( count );
	pointsArray1.element(0).move(5,10);
	pointsArray1.element(1).move(15,20);
	ArrayOfPoints pointsArray2 = pointsArray1;
	cout << "Copy of pointArray1:" << endl;
	cout << "Point_0 of array2: " << pointsArray2.element(0).getX() << "," <<
		pointsArray2.element(0).getY() << endl;
	cout << "Point_1 of array2: " << pointsArray2.element(1).getX() << "," <<
		pointsArray2.element(1).getY() << endl;

	pointsArray1.element(0).move( 15, 30 );
	pointsArray1.element(1).move( 35, 40 );
	cout << "After the moving of pointsArray1: " << endl;
	cout << "Point_0 of array2: " << pointsArray2.element(0).getX() << "," <<
		pointsArray2.element(0).getY() << endl;
	cout << "Point_1 of array2: " << pointsArray2.element(1).getX() << "," <<
		pointsArray2.element(1).getY() << endl;
}

上述例题运行报错,为什么呢?
在这里插入图片描述
这就是浅复制导致了程序出错。
在这里插入图片描述
在main中重新定义pointsArray2对象,并将pointsArray1赋值给pointsArray2:ArrayOfPoints pointsArray2 = pointsArray1;这个过程就是浅复制,执行上述代码后,就出现了图中所示的情况——两个不同的对象指向的是同一块内存地址。
所以当程序结束时,析构函数先删除了pointsArray1所在内存区域,在删除pointsArray2所在内存区域。可是,两个对象指向统一块内存区域,所以,在执行第二次删除操作是在删除一个已经不存在的对象,程序报错。

要解决这个问题,就要进行深复制。
例6_22

#include <iostream>
#include <cassert>
using namespace std;
class Point
{
public:
	Point()
		:x(0),y(0)
	{
		cout << "Default constructor called." << endl;
	}
	Point( int x, int y )
		:x(x),y(y)
	{
		cout << "Constructor called." << endl;
	}
	~Point()
	{
		cout << "Destructor called." << endl; 
	}
	int getX() const
	{
		return x;
	}
	int getY() const
	{
		return y;
	}
	void move( int newX, int newY )
	{
		x = newX;
		y = newY;
	}

private:
	int x;
	int y;
};
class ArrayOfPoints
{
public:
	ArrayOfPoints( int size )
		:size( size )
	{
		points = new Point[ size ];
	}
	ArrayOfPoints( const ArrayOfPoints &v );//复制构造函数,实现深复制
	~ArrayOfPoints()
	{
		cout << "Deleting" << endl;
		delete [] points;
	}

	Point &element( int index )
	{
		assert( index >= 0 && index < size );
		return points[ index ];
	}
private:
	Point *points;
	int size;
};

ArrayOfPoints::ArrayOfPoints( const ArrayOfPoints &v )//复制构造函数,实现深复制
{
	size = v.size;
	points = new Point[size];
	for( int i = 0; i < size; i++ )
		points[ i ] = v.points[ i ];
}

int main()
{
	int count;
	cout << "Please enter the count of points:";
	cin >> count;
	ArrayOfPoints pointsArray1( count );
	pointsArray1.element(0).move(5,10);
	pointsArray1.element(1).move(15,20);
	ArrayOfPoints pointsArray2 = pointsArray1;
	cout << "Copy of pointArray1:" << endl;
	cout << "Point_0 of array2: " << pointsArray2.element(0).getX() << "," <<
		pointsArray2.element(0).getY() << endl;
	cout << "Point_1 of array2: " << pointsArray2.element(1).getX() << "," <<
		pointsArray2.element(1).getY() << endl;

	pointsArray1.element(0).move( 15, 30 );
	pointsArray1.element(1).move( 35, 40 );
	cout << "After the moving of pointsArray1: " << endl;
	cout << "Point_0 of array2: " << pointsArray2.element(0).getX() << "," <<
		pointsArray2.element(0).getY() << endl;
	cout << "Point_1 of array2: " << pointsArray2.element(1).getX() << "," <<
		pointsArray2.element(1).getY() << endl;
}

注意,ArrayOfPoint类中增加了一个复制构造函数。
`运行结果如下:在这里插入图片描述
这次程序不崩溃的主要原因是在执行语句:

ArrayOfPoints pointsArray2 = pointsArray1;

是,执行的是复制构造函数,系统另辟一块内存给pointsArray2,来存储与pointsArray1相同的内容。
在这里插入图片描述
这样,程序结束时,析构函数删除pointsArray1时,pointsArray2所在的内存区域仍然存在,析构函数再对其进行删除操作。


我是题目,from牛客网。
这道题问,以下代码是否完全正确,执行可能得到的结果是:

class A
{
   int i;
};
class B
{
   A *p;
public:
   B(){p=new A;}
   ~B(){delete p;}
};
void sayHello(B b)
{
}
int main()
{
   B b;
   sayHello(b);
}

其结果是程序崩溃,正是浅复制导致程崩溃。
首先,main中定义了一个B类的实例b,然后执行sayHello(b);该函数接收参数b,函数中this->b= b;属于浅复制,它们指向同一块内存区域。当sayHello(b);函数运行结束时,系统删除this->b指向的内存区域,而后回到main,类b的析构函数删除b指向的内存区域,但是这块区域在sayHello(b);运行结束时,就已经被删除了,所以程序报错。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值