MST

星途 面试题库

面试题:C++ delete与delete []在内存管理机制下的深度剖析

从C++内存管理机制(如堆内存分配、对象生命周期等方面)深入分析delete与delete []的区别,以及在多重继承、虚基类等复杂继承体系下使用delete和delete []可能遇到的问题及解决方法。
31.8万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

delete 与 delete [] 的区别

  1. 针对对象类型
    • delete:用于释放单个对象的内存。例如,如果通过 new 分配了一个普通的类对象:
class MyClass {
public:
    MyClass() {}
    ~MyClass() {}
};
MyClass* obj = new MyClass();
delete obj;
  • delete []:用于释放数组形式的对象内存。当使用 new[] 分配内存时,必须使用 delete [] 来释放。例如:
MyClass* arr = new MyClass[10];
delete [] arr;
  1. 调用析构函数的次数
    • delete:只调用一次对象的析构函数,因为它处理的是单个对象。
    • delete []:会根据数组的大小,对数组中的每个元素调用析构函数。这是因为数组中的每个对象都需要被正确销毁。
  2. 内存释放方式
    • 编译器在使用 newnew[] 分配内存时,可能会在内存布局上有所不同。delete 知道如何释放单个对象的内存块,而 delete [] 知道如何释放包含多个对象的连续内存块,并正确处理每个对象的析构。

在复杂继承体系下的问题及解决方法

  1. 多重继承
    • 问题:在多重继承中,对象的内存布局会变得复杂。如果使用 delete 而不是 delete [] 来释放一个通过 new[] 分配的多重继承类对象数组,可能导致部分基类子对象的析构函数未被调用,从而造成内存泄漏。例如:
class Base1 {
public:
    Base1() {}
    virtual ~Base1() {}
};
class Base2 {
public:
    Base2() {}
    virtual ~Base2() {}
};
class Derived : public Base1, public Base2 {
public:
    Derived() {}
    ~Derived() {}
};
Derived* arr = new Derived[10];
// 错误使用delete,会导致Base2子对象析构函数未调用
delete arr; 
  • 解决方法:始终确保使用 delete [] 来释放通过 new[] 分配的对象数组。同时,将基类的析构函数声明为 virtual,这样在通过基类指针删除派生类对象时,能正确调用派生类及其基类的析构函数。
  1. 虚基类
    • 问题:虚基类在内存布局上有特殊之处,主要是为了避免多重继承中的菱形继承问题时出现数据冗余。如果在虚基类存在的情况下,错误地使用 deletedelete [],可能导致内存释放错误或析构函数调用顺序混乱。例如:
class VirtualBase {
public:
    VirtualBase() {}
    virtual ~VirtualBase() {}
};
class Derived1 : virtual public VirtualBase {
public:
    Derived1() {}
    ~Derived1() {}
};
class Derived2 : virtual public VirtualBase {
public:
    Derived2() {}
    ~Derived2() {}
};
class FinalDerived : public Derived1, public Derived2 {
public:
    FinalDerived() {}
    ~FinalDerived() {}
};
FinalDerived* obj = new FinalDerived();
// 假设错误地使用delete [](应该使用delete)
delete [] obj; 
  • 解决方法:同样,要准确匹配 newdelete 操作符(new 对应 deletenew[] 对应 delete [])。并且虚基类的析构函数也应该声明为 virtual,以确保在对象销毁时,整个继承体系中的析构函数能按正确顺序调用。此外,在使用 new[]delete [] 时要特别注意对象数组中元素的类型和继承结构,避免错误操作。