【c++语言程序设计】深层复制与浅层复制(深拷贝与浅拷贝)
浅层复制
浅层复制是指复制构造函数仅仅将对象的成员逐一复制,而不管成员类型是否是指针。如果一个类拥有指针成员并且采用浅层复制,那么复制对象时只会复制指针的地址,而不会复制指针所指向的数据。换句话说,多个对象共享同一块内存。
默认的复制构造函数,是对数据项的直接复制 (浅层复制)——编写复制构造函数的必要性
深层复制
为了避免浅层复制的问题,我们可以自定义复制构造函数,手动创建一份对象数据的“深层副本”。深层复制会为新对象分配新的内存空间,并将数据逐项复制,确保每个对象的数据独立。
浅层复制——代码(存在问题的版本)
#include <iostream>
#include <cassert>
using namespace std;
class Point {
private:
int x, y; // 坐标
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
int getX() const { return x; }
int getY() const { return y; }
void move(int newX, int newY)
{ // 移动到新坐标
x = newX;
y = newY;
}
};
class ArrayOfPoints
{
private:
Point* points; // 指向动态数组
int size;
public:
ArrayOfPoints(int size) : size(size)
{
points = new Point[size]; // 分配内存
}
~ArrayOfPoints()
{
delete[] points; // 释放内存
}
Point& element(int index) { // 返回引用,方便修改
assert(index >= 0 && index < size);
return points[index];
}
};
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 的坐标
pointsArray1.element(0).move(25, 30);
pointsArray1.element(1).move(35, 40);
// 输出 pointsArray2 的坐标,观察浅层复制的问题
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;
}
问题: pointsArray1
和 pointsArray2
共用了同一块内存,因此移动 pointsArray1
中的点也会影响 pointsArray2
中的点。
默认的复制构造函数将两个对象的对应数据项简单复制后,pointsArrayl 的成员 points 和 pointsArray2 的成员 points具有相同的值,也就是说两个指针指向的是同一内存地址,表面上好像完成了复制,但是并没有形成真正的副本。因此当程序中移动 pointsArrayl 中的点时,也影响到了 pointsArray2。 这种效果就是“浅层复制”。
浅层复制还有更大的弊病,在程序结束之前 pointsArrayl 和pointsArray2 的析构函数会自动被调用,动态分配的内存空间会被释放。由于两个对象共用了同一块内存空间,因此该空间被两次释放,于是导致运行错误。
此问题可以通过实现深层复制解决【编写复制构造函数】
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 {
private:
int x, y; // 坐标
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
int getX() const { return x; }
int getY() const { return y; }
void move(int newX, int newY) { // 移动到新坐标
x = newX;
y = newY;
}
};
class ArrayOfPoints {
private:
Point* points; // 指向动态数组
int size;
public:
ArrayOfPoints(int size) : size(size) {
points = new Point[size]; // 分配内存
}
// 实现深层复制构造函数
ArrayOfPoints(const ArrayOfPoints& v) : size(v.size) {
points = new Point[size]; // 分配新内存
for (int i = 0; i < size; i++) {
points[i] = v.points[i]; // 逐一复制数组中的点
}
}
~ArrayOfPoints() {
delete[] points; // 释放内存
}
Point& element(int index) { // 返回引用,方便修改
assert(index >= 0 && index < size);
return points[index];
}
};
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);
// 使用深层复制构造函数创建 pointsArray2
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 的坐标
pointsArray1.element(0).move(25, 30);
pointsArray1.element(1).move(35, 40);
// 输出 pointsArray2 的坐标,验证深层复制是否正确
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;
}
总结
-
浅层复制适用于类成员无指针、无动态内存的简单场景。
-
深层复制适用于包含动态内存的类,确保每个对象拥有独立的数据副本,避免共享内存和双重释放问题。
参考教材:C++语言程序设计 (第5版) 郑莉 董渊 编著
原文地址:https://blog.csdn.net/Z15922342915/article/details/143497168
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!