MST

星途 面试题库

面试题:C++ 中拷贝构造函数性能优化之浅拷贝与深拷贝

请解释在 C++ 中浅拷贝和深拷贝的区别,并说明在什么场景下使用深拷贝来优化拷贝构造函数的性能,同时请给出一个浅拷贝可能导致问题的示例代码,并将其修改为深拷贝以解决问题。
47.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

浅拷贝和深拷贝的区别

  1. 浅拷贝
    • 浅拷贝只是简单地复制对象的成员变量的值。对于指针类型的成员变量,浅拷贝会使多个对象的指针指向同一块内存地址。
    • 当对象被销毁时,如果多个对象的指针指向同一块内存,可能会导致内存重复释放(double - free)问题,同时也可能在对象生命周期管理上出现混乱。
  2. 深拷贝
    • 深拷贝不仅复制对象的成员变量的值,对于指针类型的成员变量,会重新分配一块新的内存,并将原指针所指向内存的内容复制到新分配的内存中。这样每个对象都有自己独立的内存空间,避免了内存重复释放等问题。

使用深拷贝优化拷贝构造函数性能的场景

当类中包含动态分配的资源(如指针指向的堆内存),并且希望在拷贝对象时,每个对象都拥有自己独立的资源副本,而不是共享资源时,就需要使用深拷贝来优化拷贝构造函数。例如,当一个类表示一个字符串,其内部使用动态分配的字符数组来存储字符串内容时,使用深拷贝可以确保每个拷贝对象都有自己独立的字符串副本,在对象生命周期内可以安全地操作字符串,而不会影响其他对象。

浅拷贝可能导致问题的示例代码

#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.strs2.str 指向同一块内存。当 s1s2 先后被销毁时,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 的内容复制到新分配的内存中,这样 s1s2 拥有各自独立的字符串副本,避免了浅拷贝带来的内存重复释放问题。