首先先谈动态内存分配,主要是在程序运行期间,申请内存空间,用到操作符new,例如申请一个数组空间:int *arr = new int[10];
,指针arr指向数组空间的初始地址即首元素地址;
当使用完动态内存分配的空间后,如若不需要再使用,应该主动释放掉,否则容易导致内存泄漏。释放内存操作符delete:例如释放数组空间:delete[] arr;
,对于对象内存释放:delete 指针p
谈浅拷贝:只能实现对象间数据元素的一一对应的复制,而对于指针来说,只拷贝了指针本身,但没有拷贝指针所指向的对象,因此倘若改变原数据,则副本也会受到影响,因为两者指针指向了相同的内存空间。
谈深拷贝:当被复制的对象数据成员是指针类型时,不应该只是复制该指针成员本身,而是要将指针所指的对象进行复制,其中要涉及到用new为副本开辟新的内存空间,只有这样,原数据与副本虽然最初内容相同,但是两者所占的内存位置完全不同,并不会互相影响。
举例如下:
首先先观察浅拷贝的结果(如下程序),从输出结果可以看出,a2是对a1进行的浅拷贝,只是拷贝了数组arr指针的本身,因为当对a1数组进行修改时,a2的数组也受到了影响,因为两个所指向的内存空间一致。
class A {
public:
int *arr;
A(int n) {//构造函数
arr = new int[n];
}
A(const A& a) {//复制构造函数
arr = a.arr;
}
};
int main() {
A a1(1);
a1.arr[0] = 1;
printf("对象a1的数据:%d\n", a1.arr[0]);
A a2 = a1;
printf("对象a2的数据:%d\n", a2.arr[0]);
a1.arr[0] = 2;//对象a1数据修改为2
printf("仅对象a1数据修改后:\n");
printf("对象a1的数据:%d\n", a1.arr[0]);
printf("对象a2的数据:%d\n", a2.arr[0]);
}
/*输出
对象a1的数据:1
对象a2的数据:1
仅对象a1数据修改后:
对象a1的数据:2
对象a2的数据:2
*/
接下来,举例深拷贝,修改一下上面代码为,从输出结果可以看出,深拷贝实现了两个对象的数组分别占用不同的内存空间,因为两个不会互相影响。
class A {
public:
int *arr;
A(int n) {//构造函数
arr = new int[n];
}
A(const A& a) {//复制构造函数
int n = sizeof(a.arr) / 4;
arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = a.arr[i];
}
}
};
int main() {
A a1(1);
a1.arr[0] = 1;
printf("对象a1的数据:%d\n", a1.arr[0]);
A a2 = a1;
printf("对象a2的数据:%d\n", a2.arr[0]);
a1.arr[0] = 2;//对象a1数据修改为2
printf("仅对象a1数据修改后:\n");
printf("对象a1的数据:%d\n", a1.arr[0]);
printf("对象a2的数据:%d\n", a2.arr[0]);
}
/*输出:
对象a1的数据:1
对象a2的数据:1
仅对象a1数据修改后:
对象a1的数据:2
对象a2的数据:1(update)
*/