深复制浅复制的一点理解
讨论这个问题主要是为了知道既然有默认的复制构造函数为什么有时候还要自己写复制构造函数。
代码有点长,主要看结构。
这是一个浅复制的例子,用了默认的复制构造函数,结果程序崩了。看看为什么
#include<iostream>
#include<cassert>
using namespace std;
class Point
{
public:
Point() :x(0), y(0)
{
cout << "Defualt 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, y;
};
class ArrayOfPoints
{
public:
ArrayOfPoints(int size) :size(size)
{
points = new Point[size];
}
~ArrayOfPoints()
{
cout << "Deleting..." << endl;
delete[] points;
}
Point &element(int index)
{
assert(index >= 0 && index < size);
return points[index];
}
private:
Point * points;
int size;
};
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 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;
pointsArray1.element(0).move(25, 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;
return 0;
}
这是一个深复制的例子,解决了上面崩掉的程序,再看看为什么
两者的不同在于下面的加了这么一块代码:
也就是自己写了一个复制构造函数
ArrayOfPoints(const ArrayOfPoints &v);
....
ArrayOfPoints::ArrayOfPoints(const ArrayOfPoints &v)
{
size = v.size;
points = new Point[size];
for (int i = 0; i < size; i++)
points[i] = v.points[i];
}
#include<iostream>
#include<cassert>
using namespace std;
class Point
{
public:
Point() :x(0), y(0)
{
cout << "Defualt 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, y;
};
class ArrayOfPoints
{
public:
ArrayOfPoints(const ArrayOfPoints &v);
ArrayOfPoints(int size) :size(size)
{
points = new Point[size];
}
~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 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;
pointsArray1.element(0).move(25, 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;
return 0;
}
上面的ArrayPoint是动态数组类, pointsArray1 ,2 都是动态数组对象,对象的成员有size指明该数组的大小和points这个指针,指向另一个类Point。
实际上,在用 ArrayOfPoints pointsArray2=pointsArray1 创建对象的副本的时候,他们的成员,points有相同的值,也就是这个points指针指向的是同一个内存地址,其实并没有完成所谓的复制,只是把指针指过去了,可以访问同样的内容了。所以程序中的move函数移动点的位置的时候,pointArray1的point移动了直接影响pointArray2的point的位置。 程序崩掉的原因也是因为他们指向相同的内存单元,程序结束前要调用析构函数,动态分配的内存空间要释放,但是他们指向相同的内存空间,该空间要别释放两次,学析构函数的时候就说了不允许这样,程序就运行错误了。 这就是浅复制的弊病。
当自己写了复制构造函数之后,pointsArray2的point指针有了自己指向的内存空间,问题就迎刃而解了。