MST

星途 面试题库

面试题:C++中delete []与内存管理的复杂场景

假设你有一个类继承体系,基类有虚析构函数。现在通过new []创建了一个派生类对象的数组,在使用delete []释放这个数组时,会发生什么?请详细说明内存释放的过程以及可能遇到的问题,并提供相应的代码示例及解决方案。
40.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 内存释放过程
    • 当使用delete []释放通过new []创建的派生类对象数组时,首先会从数组的最后一个元素开始,依次调用每个派生类对象的析构函数。由于基类有虚析构函数,这里会调用派生类的析构函数(如果派生类有自己的析构函数重写),然后再调用基类的析构函数。
    • 完成所有对象析构函数的调用后,系统会释放分配给这个数组的内存空间。
  2. 可能遇到的问题
    • 如果基类析构函数不是虚函数,在使用delete []释放派生类对象数组时,只会调用基类的析构函数,而不会调用派生类的析构函数。这会导致派生类中申请的资源(如动态分配的内存等)无法释放,从而造成内存泄漏。
  3. 代码示例
#include <iostream>
#include <string>

// 基类
class Base {
public:
    // 基类非虚析构函数(错误示例,应改为虚析构函数)
    // ~Base() {}
    virtual ~Base() {
        std::cout << "Base destructor called" << std::endl;
    }
};

// 派生类
class Derived : public Base {
private:
    std::string data;
public:
    Derived(const std::string& s) : data(s) {
        std::cout << "Derived constructor called" << std::endl;
    }
    ~Derived() {
        std::cout << "Derived destructor called for " << data << std::endl;
    }
};

int main() {
    Base* arr[] = {new Derived("obj1"), new Derived("obj2")};
    for (size_t i = 0; i < 2; ++i) {
        delete arr[i];
    }
    // 或者如果是new []创建的数组
    // Base* arr = new Derived[2]{"obj1", "obj2"};
    // delete [] arr;
    return 0;
}
  1. 解决方案
    • 确保基类的析构函数声明为虚函数,如上述代码中修改后的Base类的析构函数。这样在通过delete []释放派生类对象数组时,会正确地调用每个派生类对象的析构函数,进而正确释放所有资源。

如果是new []创建数组并释放,示例代码如下:

#include <iostream>
#include <string>

class Base {
public:
    virtual ~Base() {
        std::cout << "Base destructor called" << std::endl;
    }
};

class Derived : public Base {
private:
    std::string data;
public:
    Derived(const std::string& s) : data(s) {
        std::cout << "Derived constructor called" << std::endl;
    }
    ~Derived() {
        std::cout << "Derived destructor called for " << data << std::endl;
    }
};

int main() {
    Base* arr = new Derived[2]{"obj1", "obj2"};
    delete [] arr;
    return 0;
}