当类的指针实例超出范围时不调用析构函数是真的吗?

Posted

技术标签:

【中文标题】当类的指针实例超出范围时不调用析构函数是真的吗?【英文标题】:Is it true that destructors aren't called when a pointer instance of a class goes out of scope? 【发布时间】:2015-12-30 11:35:33 【问题描述】:

以这段代码为例:

  class MyClass
   
   public:
  ~MyClass()
   
     cout << "Destructor called\n";
    
   ;

  int main()
   
      MyClass Testvar;
      //  destructer called for this
      MyClass *ptrvar;
      ptrvar = &Testvar;
      // but not for this
   

这给我带来了很多困惑。上面的代码打印: 析构函数调用 只有一次。我在 main 中声明了两个 MyClass 实例,其中一个是 MyClass 类型的普通变量,另一个是指向普通变量的相同类型的指针。这里不需要析构函数(没有动态分配),但为了举例,我在类中定义了一个。因此,因为定义了两个类实例,所以应该调用两次析构函数。但是当我运行这段代码时,这并没有发生。如果我删除指针并再定义一个普通实例,程序会打印:

调用的析构函数 调用析构函数

我的观察是,当指针实例超出范围时,不会隐式调用析构函数。我是对的还是只是错过了什么。

【问题讨论】:

What are the barriers to understanding pointers and what can be done to overcome them?的可能重复 【参考方案1】:

我在 main 中声明了两个 MyClass 实例

不,你没有。您声明了MyClass 的一个实例,并创建了一个指向该实例的指针。就是这样。

您的代码的行为是正确的。

我的观察是,当指针实例超出范围时,不会隐式调用析构函数。我是对的还是只是错过了什么。

没错。 C++ 不提供garbage collector。你必须自己跟踪你的指针。您可以使用smart pointers 来执行此操作。

【讨论】:

【参考方案2】:

您只创建了一个对象,并且仅为该对象调用析构函数。

指针不实例化另一个对象,它只是指向前一个对象

当分配在堆栈上的对象超出范围以及动态创建的对象(使用 operator new)被显式销毁(operator delete)时,将调用析构函数

【讨论】:

【参考方案3】:

您实际上只实例化了一个MyClass 类型的对象。这发生在这一行:

MyClass Testvar;

在下一行中,您只声明了一个指向MyClass 类型对象的指针,但这并没有创建一个新对象:

MyClass *ptrvar;

在这一行中,您将第一个 MyClass 的地址分配给了您的指针:

ptrvar = &Testvar;

所以指针指向的是同一个对象,你仍然只有一个MyClass 的实例。当作用域关闭时,TestVar 被删除,您会看到析构函数被调用了一次。

您可以创建一个新的MyClass 对象(在堆上)并将其地址分配给您的指针,如下所示:

MyClass *ptrvar = new MyClass();

现在你确实有两个MyClass 对象。但是,当范围关闭时,您仍然会看到只有一个对象被删除。这是因为new 在堆上而不是在堆栈上创建一个对象,并且这些对象在创建它们的作用域结束时不会自动删除。您必须使用 delete 手动执行此操作:

delete ptrvar;

当这行代码执行时,你会看到你的析构函数被调用了。如果你不这样做,你就会把你的对象留在堆上,并“泄漏”它占用的内存。

为了避免手动执行所有这些操作,您应该使用 C++ 提供的内置智能指针。

【讨论】:

以上是关于当类的指针实例超出范围时不调用析构函数是真的吗?的主要内容,如果未能解决你的问题,请参考以下文章

C ++:在超出范围之前调用析构函数?

c++中,析构函数和delete各有啥作用啊

C++ 虚拟析构函数 (virtual destructor)

静态对象成员会在所属类的析构函数被调用时自动析构吗?

堆栈上的对象被覆盖时不调用析构函数

unity c#怎么调用析构函数