【问题标题】:C++ delete operator and destructor:what do they actually do and what are the differences of the two?C++删除运算符和析构函数:它们实际上是做什么的,两者有什么区别?
【发布时间】:2021-08-30 11:01:32
【问题描述】:

我试图在 C++ 中找出删除运算符和析构函数之间的区别,并尝试使用以下两个 sn-ps(我使用 Visual Studio 2019 编译它们):

代码 1:

#include <stdio.h>
class A
{
    public:
        A() { a = new int; *a = 42; b = 33; }
        ~A()
        {
            printf("destructor!\n");
            delete a;
        }

        int* a;
        int  b;
};

int main(int argc, const char** argv)
{
    A* myA = new A();
    printf("a:%d  b:%d\n", *(myA->a), myA->b);
    //delete myA;
    myA->~A();
    printf("b:%d\n", myA->b);
    printf("a:%d\n", *(myA->a));
}

code2:(和code 1差不多,只是将use delete改为使用destructor)

#include <stdio.h>
class A
{
    public:
        A() { a = new int; *a = 42; b = 33; }
        ~A()
        {
            printf("destructor!\n");
            delete a;
        }

        int* a;
        int  b;
};

int main(int argc, const char** argv)
{
    A* myA = new A();
    printf("a:%d  b:%d\n", *(myA->a), myA->b);
    delete myA;
    //myA->~A();
    printf("b:%d\n", myA->b);
    printf("a:%d\n", *(myA->a));
}

代码1的结果是:

在运行代码 2 时抛出异常: , 控制台是:

从结果我猜,当你运行 myA->~A() 时,它只是执行了定义的析构函数,即 delete a,使这个指针成为悬空指针。 当您运行 delete myA 时,它不会同时执行析构函数,并使指针 myA 成为悬空指针。但我不确定这些具体是如何实现的。

两个结果不同的解释是我的第一个问题

第二个问题s:sn-p的代码是从Here复制过来的,结果也和我的不一样,希望哪位大神也能解释一下

【问题讨论】:

  • 您是否阅读了有关您链接的问题的答案?他们解释说代码的第一个版本具有未定义的行为(第二个版本也有 UB 出于类似原因),即输出可以是任何东西。答案也解决了您的第一个问题
  • 这能回答你的问题吗? stackoverflow.com/questions/14215140/…。为什么不呢?
  • 这能回答你的问题吗? stackoverflow.com/questions/16908650/…
  • 你也应该试试这个变种int main() { A a; }
  • @463035818_is_not_a_number 在您的第一个链接中,答案是“调用析构函数会释放对象拥有的资源,但不会释放分配给对象本身的内存。”我不太清楚资源与分配给对象的内存的区别。

标签: c++ destructor


【解决方案1】:

delete myA; 是一个delete expression。如果myA不是nullptr,它会先调用myA指向的对象的析构函数(如果指向的类型有析构函数),然后释放对象之前分配的存储空间new expression

myA-&gt;~A(); 显式调用myA 指向的对象的析构函数。它不会释放先前分配的存储空间。在这种情况下,您正在泄漏与A 关联的内存。除非您使用placement new(您的示例中未使用的高级语言功能),否则显式调用析构函数几乎肯定是错误的。

关于printf("b:%d\n", myA-&gt;b);printf("a:%d\n", *(myA-&gt;a)); 在这两个示例中的输出,这些都会导致未定义的行为。

当您执行delete myA; 时,指针myA 现在有一个无效的指针值(通常称为“悬空指针”),不允许您取消引用。在printf 中你都尝试myA-&gt; 这是未定义的行为,所以结果是没有意义的。

当您执行myA-&gt;~A(); 时,指针myA 仍然指向有效存储,但它不再指向AA 被破坏了。因此,类似地,尝试取消引用myA 也将是未定义行为,导致无意义的输出。

您的印象似乎是,如果运行您的代码不会产生可见的错误,那么它一定没问题。但这在 C++ 中是不正确的。许多错误会导致未定义的行为,这不需要崩溃或给出任何明确的诊断,即出现问题。 myA-&gt;~A(); 示例没有导致运行时错误这一事实并不意味着它比使用 delete myA; 的示例更不正确。

【讨论】:

  • 感谢您的解释。如果我打个比方,比如说放风筝,那么 delete myA 意味着电线被切断,同时调用析构函数 myA->~A();意思是风筝本身坏了,不是电线坏了?
  • @LeonloveKaren 不,一点也不。 delete 包括调用析构函数。所以无论析构函数在你的类比中做了什么,delete 表达式都会这样做,并且无论类比的清理内存版本是什么。
猜你喜欢
  • 2013-02-14
  • 2018-11-29
  • 2013-05-30
  • 2014-02-05
  • 1970-01-01
  • 1970-01-01
  • 2017-08-18
  • 1970-01-01
  • 2011-09-04
相关资源
最近更新 更多