简述一下浅拷贝和深拷贝
浅拷贝的问题、深拷贝的实现
标准回答
浅拷贝和深拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是“引用”。浅拷贝和深拷贝一般在拷贝构造函数和赋值运算符重载函数中涉及到。
浅拷贝
浅拷贝又称为值拷贝,将源对象的值拷贝到目标对象中,如果对象中有某个成员是指针类型数据,并且是在堆区创建,则使用浅拷贝仅仅拷贝的是这个指针变量的值,也就是在目标对象中该指针类型数据和源对象中的该成员指向的是同一块堆空间。这样会带来一个问题,就是在析构函数中释放该堆区数据,会被释放多次。默认的拷贝构造函数和默认的赋值运算符重载函数都是浅拷贝。
深拷贝
深拷贝在拷贝的时候先开辟出和源对象大小一样的空间,然后将源对象里的内容拷贝到目标对象中去,这样指针成员就指向了不同的内存位置。并且里面的内容是一样的,这样不但达到了拷贝的目的,还不会出现问题,两个对象先后去调用析构函数,分别释放自己指针成员所指向的内存。即为每次增加一个指针,便申请一块新的内存,并让这个指针指向新的内存,深拷贝情况下,不会出现重复释放同一块内存的错误。
浅拷贝和深拷贝示例代码:
class Person { public: char* m_Name; // 姓名 int m_Age; // 年龄 Person() { m_Name = nullptr; m_Age = 0; } Person(const char* name, int age) { cout << "有参构造函数执行了..." << endl; m_Name = new char[strlen(name) + 1]; strcpy(m_Name, name); m_Age = age; } // 深拷贝 Person(const Person& p) { m_Name = new char[strlen(p.m_Name) + 1]; // 重新开辟空间 strcpy(m_Name, p.m_Name); // 拷贝内容 m_Age = p.m_Age; } // 浅拷贝 /*Person(const Person& p) { m_Name = p.m_Name; // 仅仅是值拷贝 m_Age = p.m_Age; }*/ ~Person() { cout << "析构函数执行了..." << endl; if (m_Name != nullptr) { delete[] m_Name; m_Name = nullptr; } } }; int main() { Person p1("Tom", 20); cout << "p1的姓名:" << p1.m_Name << " p1的年龄:" << p1.m_Age << endl; Person p2 = Person(p1); cout << "p2的姓名:" << p2.m_Name << " p2的年龄:" << p2.m_Age << endl; return 0; }
这道题你会答吗?花几分钟告诉大家答案吧!
扫描二维码,关注牛客网
下载牛客APP,随时随地刷题
得分点
浅拷贝的问题、深拷贝的实现
参考答案
标准回答
浅拷贝和深拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是“引用”。浅拷贝和深拷贝一般在拷贝构造函数和赋值运算符重载函数中涉及到。
浅拷贝
浅拷贝又称为值拷贝,将源对象的值拷贝到目标对象中,如果对象中有某个成员是指针类型数据,并且是在堆区创建,则使用浅拷贝仅仅拷贝的是这个指针变量的值,也就是在目标对象中该指针类型数据和源对象中的该成员指向的是同一块堆空间。这样会带来一个问题,就是在析构函数中释放该堆区数据,会被释放多次。默认的拷贝构造函数和默认的赋值运算符重载函数都是浅拷贝。
深拷贝
深拷贝在拷贝的时候先开辟出和源对象大小一样的空间,然后将源对象里的内容拷贝到目标对象中去,这样指针成员就指向了不同的内存位置。并且里面的内容是一样的,这样不但达到了拷贝的目的,还不会出现问题,两个对象先后去调用析构函数,分别释放自己指针成员所指向的内存。即为每次增加一个指针,便申请一块新的内存,并让这个指针指向新的内存,深拷贝情况下,不会出现重复释放同一块内存的错误。
延伸阅读
浅拷贝和深拷贝示例代码: