面试题答案
一键面试浅拷贝和深拷贝的区别
- 浅拷贝:
- 浅拷贝只是简单地复制对象的成员变量的值。对于指针类型的成员变量,浅拷贝会使多个对象的指针指向同一块内存地址。
- 当对象被销毁时,如果多个对象的指针指向同一块内存,可能会导致内存重复释放(double - free)问题,同时也可能在对象生命周期管理上出现混乱。
- 深拷贝:
- 深拷贝不仅复制对象的成员变量的值,对于指针类型的成员变量,会重新分配一块新的内存,并将原指针所指向内存的内容复制到新分配的内存中。这样每个对象都有自己独立的内存空间,避免了内存重复释放等问题。
使用深拷贝优化拷贝构造函数性能的场景
当类中包含动态分配的资源(如指针指向的堆内存),并且希望在拷贝对象时,每个对象都拥有自己独立的资源副本,而不是共享资源时,就需要使用深拷贝来优化拷贝构造函数。例如,当一个类表示一个字符串,其内部使用动态分配的字符数组来存储字符串内容时,使用深拷贝可以确保每个拷贝对象都有自己独立的字符串副本,在对象生命周期内可以安全地操作字符串,而不会影响其他对象。
浅拷贝可能导致问题的示例代码
#include <iostream>
#include <cstring>
class String {
public:
char* str;
int length;
String(const char* s) {
length = strlen(s);
str = new char[length + 1];
strcpy(str, s);
}
// 这里默认的拷贝构造函数是浅拷贝
String(const String& other) {
length = other.length;
str = other.str;
}
~String() {
delete[] str;
}
};
int main() {
String s1("Hello");
String s2(s1);
return 0;
}
在上述代码中,String
类默认的拷贝构造函数是浅拷贝。当 s2
通过拷贝 s1
创建时,s1.str
和 s2.str
指向同一块内存。当 s1
和 s2
先后被销毁时,str
所指向的内存会被重复释放,导致程序崩溃。
修改为深拷贝的代码
#include <iostream>
#include <cstring>
class String {
public:
char* str;
int length;
String(const char* s) {
length = strlen(s);
str = new char[length + 1];
strcpy(str, s);
}
// 深拷贝构造函数
String(const String& other) {
length = other.length;
str = new char[length + 1];
strcpy(str, other.str);
}
~String() {
delete[] str;
}
};
int main() {
String s1("Hello");
String s2(s1);
return 0;
}
在修改后的代码中,深拷贝构造函数为 str
重新分配了内存,并将 other.str
的内容复制到新分配的内存中,这样 s1
和 s2
拥有各自独立的字符串副本,避免了浅拷贝带来的内存重复释放问题。