我们以对象的复制为例,解释深复制与浅复制的概念:
例题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);
运行结束时,就已经被删除了,所以程序报错。