面试题答案
一键面试浅拷贝和深拷贝的区别
- 浅拷贝:
- 在浅拷贝中,移动构造函数只是简单地将源对象的指针或引用等成员变量的值复制到目标对象。如果类中有指针成员,浅拷贝后,源对象和目标对象的指针会指向同一块内存。这就导致当其中一个对象销毁时,释放了该内存,另一个对象的指针就会变成野指针,从而引发内存错误(如悬空指针错误)。
- 例如,假设有一个类
MyClass
包含一个int*
类型的指针成员data
,浅拷贝的移动构造函数可能只是简单地this->data = other.data
。
- 深拷贝:
- 深拷贝则会在移动构造函数中为目标对象的指针成员重新分配内存,并将源对象指针所指向的内容复制到新分配的内存中。这样,源对象和目标对象的指针虽然内容相同,但指向不同的内存区域。当其中一个对象销毁时,不会影响另一个对象的内存。
- 继续以上面
MyClass
类为例,深拷贝的移动构造函数会先this->data = new int[length]
(假设length
是数据长度),然后通过循环将other.data
的内容复制到this->data
中。
性能优化场景下的选择
- 选择浅拷贝的场景:
- 当类的资源管理方式支持共享资源,并且对象的生命周期能够妥善管理以避免悬空指针等问题时,可以选择浅拷贝。例如,在智能指针的实现中,引用计数机制可以保证多个智能指针共享同一资源,当最后一个引用该资源的智能指针销毁时,才释放资源。在这种情况下,浅拷贝(移动语义中的浅拷贝)可以高效地转移资源所有权,减少内存分配和释放的开销。
- 当对象的复制操作非常频繁,并且对象内部资源占用较小,重新分配内存的开销相对较大时,浅拷贝可以提高性能。因为它避免了每次复制都进行内存分配和数据复制的操作。
- 选择深拷贝的场景:
- 当需要确保源对象和目标对象完全独立,互不影响时,必须选择深拷贝。比如在某些数据处理场景中,每个对象都需要有自己独立的数据副本,对一个对象数据的修改不能影响其他对象。
- 如果类中的资源管理方式不适合共享,例如资源是一些独占的硬件设备句柄等,深拷贝可以保证每个对象都有自己独立的资源,避免资源冲突。