当delete和析构函数都被调用时,两者之间的区别是什么? 我对C++中的析构函数感到困惑。例如,当我们在下面的代码中调用delete时,它首先调用Derived1的析构函数,然后调用Base的析构函数,然后会发生什么?动态分配的指针呢? 另外,如果我不删除直接调用Derived1的析构函数,或者同时调用它们,会发生什么 #include <iostream> using namespace std; class Base { public: Base(){ cout << "Base Constructor Called\n"; } ~Base(){ cout << "Base Destructor called\n"; } }; class Derived1: public Base { public: Derived1(){ cout << "Derived constructor called\n"; } ~Derived1(){ cout << "Derived destructor called\n"; } }; int main() { Derived1 *b = new Derived1(); delete b; } #包括 使用名称空间std; 阶级基础 { 公众: Base(){ cout

当delete和析构函数都被调用时,两者之间的区别是什么? 我对C++中的析构函数感到困惑。例如,当我们在下面的代码中调用delete时,它首先调用Derived1的析构函数,然后调用Base的析构函数,然后会发生什么?动态分配的指针呢? 另外,如果我不删除直接调用Derived1的析构函数,或者同时调用它们,会发生什么 #include <iostream> using namespace std; class Base { public: Base(){ cout << "Base Constructor Called\n"; } ~Base(){ cout << "Base Destructor called\n"; } }; class Derived1: public Base { public: Derived1(){ cout << "Derived constructor called\n"; } ~Derived1(){ cout << "Derived destructor called\n"; } }; int main() { Derived1 *b = new Derived1(); delete b; } #包括 使用名称空间std; 阶级基础 { 公众: Base(){ cout,c++,debugging,C++,Debugging,在调用对象的析构函数后,正如您在问题中所指出的,delete表达式调用operator delete,这是一个释放内存的特殊函数,operator delete释放b指向的内存分配,该内存分配以前是通过调用opera分配的tor new(代码中的new表达式调用了它) 解除分配发生后(即operator delete返回后),指针b无效,无法再使用 调用析构函数直接结束指向对象的生存期(也将调用基析构函数和成员析构函数),但不会通过调用操作符delete来释放内存。您可以重用对象占用的内存和指针

在调用对象的析构函数后,正如您在问题中所指出的,
delete
表达式调用
operator delete
,这是一个释放内存的特殊函数,
operator delete
释放
b
指向的内存分配,该内存分配以前是通过调用
opera分配的tor new
(代码中的
new
表达式调用了它)

解除分配发生后(即
operator delete
返回后),指针
b
无效,无法再使用

调用析构函数直接结束指向对象的生存期(也将调用基析构函数和成员析构函数),但不会通过调用
操作符delete
来释放内存。您可以重用对象占用的内存和指针指向的内存,将新对象放入其中(使用所谓的placement new expression),但您在其上调用析构函数的对象将不再可用。尝试使用它将导致未定义的行为。(对于具有普通析构函数pre-C++20的类类型,也有例外。)

调用(非平凡的)析构函数后,在指针上使用
delete
表达式会导致未定义的行为,因为
delete
再次调用析构函数,但在对象的生命周期之外,该生命周期由上一次析构函数调用结束

调用
delete
后调用析构函数也会导致未定义的行为,因为它会使用无效指针

当我们在下面的代码中调用delete时,它首先调用Derived1的析构函数,然后调用Base的析构函数

严格来说,
delete
只销毁最派生的对象,在这种情况下,它是
Derived1
的析构函数。它是
Derived1
的析构函数,调用它自己的子对象(如
Base
)的析构函数

那会发生什么

将使用指针值作为操作数调用解除分配函数。该函数将释放先前分配的内存,从而结束存储区域的持续时间。然后,该区域可重新用于存储使用
表达式创建的其他动态对象

如果我直接调用Derived1的析构函数会发生什么

然后,对象将被销毁。销毁结束了对象的生命周期,并且(因为该类不是可平凡地销毁的)调用析构函数

不删除

这样,内存分配将不会被释放,并且无法用于进一步的分配。这通常被认为是“内存泄漏”

当我叫他们两个的时候会发生什么

#include <iostream>

using namespace std;

class Base
{
public:
    Base(){
        cout << "Base Constructor Called\n";
    }
    ~Base(){
        cout << "Base Destructor called\n";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor called\n";
    }
    ~Derived1(){
        cout << "Derived destructor called\n";
    }
};

int main()
{
    Derived1 *b = new Derived1();
    delete b;
}

那么程序的行为将是未定义的。

生存期或可用性/存在时间跨度:

  • 对象
    从它被声明和定义开始,带/不带 范围内的对象初始化,直至运行点(当前 IP as(低级别)退出该范围,在该范围内 执行对象的析构函数以恢复所有内存 要求并做其他必要的维护工作

  • 分配内存请求(通过new、malloc等指令向操作系统请求)
    从该指令用指针请求开始 在内部创建并作为唯一的基本引用返回,最多 再次引用该指针以恢复声明的内存部分 按删除说明
    但对于对象内存分配,它将自动调用其析构函数

    a_类*p=新的a_类(1,2,3);

    (1,2,3)是的初始化 被p指针引用的对象

    当然,指针的生命周期是 与前面解释的相同,如果它是通过退出其范围来完成的 在执行删除之前,内存保持保留、备用和不变的状态, 由操作系统激活将占用内存资源,因此 理解记忆泄漏的含义/术语


  • 非常感谢您的回答!我仍然对只调用Derived1的析构函数感到困惑,为什么我们不能使用内存分配进行进一步的分配?据我所知,只有*d1的属性被删除了,这样我们就可以使用另一个对象的指针,我想它会起作用。@Sydney.Ka至少一个对象可以使用任何内存区域任何执行点(存在子对象共享其地址等例外情况)。因此,分配函数必须跟踪已分配的内存。分配函数必须等到释放内存后才能重新使用内存进行另一次分配。您可以一直使用分配,直到释放它为止。