【问题标题】:Do I need to destroy each instance of new class?我需要销毁新类的每个实例吗?
【发布时间】:2017-05-01 05:57:45
【问题描述】:

本质上,如果我创建一个新类的多个实例,我是否需要为每个实例调用析构函数,或者在销毁每个实例后调用它(如果我使用模糊/错误的术语,构造函数/析构函数,我深表歉意是我还没有完全掌握的概念)。

更具体地说,这是我正在使用的一些代码(如果样式不好,我将不得不再次道歉,我有一个关于学校问题的想法,并希望尽快得到代码)。

while(read >> f >> l >> t >> s >> sta >> acct >> bal)
{
    cout << "test" << endl;
    ptr[i] = new account(f,l,t,s,sta,acct,bal);
    ptr[i]->printcontents();
    cout << "test" << endl;
    i++;
    cout << i << endl;
}

因此,为了这个问题,假设这将循环 3 次。我是否只需要调用一次“帐户”的析构函数来销毁所有三个新帐户实例,还是一个调用会留下另外两个?这甚至是一个好习惯吗?

编辑:我注意到我的一些帖子被截断了,所以我添加了最后几行,但人们已经解决了这个问题。我是用户指针的原因纯粹是因为任务要求我这样做;坦率地说,我现在没有看到使用它们的意义,但我认为它们会在某个地方变得有用。我还应该补充一点,动态内存分配也应该在分配中使用。

【问题讨论】:

  • 使用智能指针(即shared_ptr/make_sharedunique_ptr/make_unique),不要担心删除您的newed 实例。
  • 一如既往:每个new 都需要一个delete,每个new[] 恰好需要一个delete[]。但是,您基本上从不需要newnew[] 开始的频率更低。
  • 真正的问题是为什么要使用指针开始。您来自 Java,所有对象都是用new 创建的吗?您的account 对象数组可以只存储实际的account 对象
  • 您不会在 C++ 中调用析构函数(除非在极少数情况下,如果有的话,您将很长时间不会遇到)。 deletedelete[] 这样做是他们操作的一部分,自动对象的销毁也是如此。

标签: c++ pointers constructor destructor


【解决方案1】:

析构函数会自动调用,您通常不必担心它除非您使用new动态分配内存。

在这种情况下,一旦您不再需要它,您将不得不为每个分配的内存调用delete

请注意,如果您使用 new [] 分配数组,则必须使用 delete[] 进行取消分配:

int *a = new int[10]; // allocating an array of 10 integers

//...

delete[] a; // release memory

在现代 C++ 中,您应该考虑使用托管指针来完成这项工作。比如:

while(read >> f >> l >> t >> s >> sta >> acct >> bal)
{
    cout << "test" << endl;
    ptr[i] = std::make_unique<account>(f,l,t,s,sta,acct,bal);
    ptr[i]->printcontents();
    cout << "test" << endl;
    i++;
    cout << i << endl;
}

这里,std::make_unique 将返回一个 std::unique_ptr,它会在相关内存被销毁时调用 delete。


最后一点:你确定你真的需要指针吗?从您的示例中很难说,但根据您的使用情况,您也可以创建静态分配的对象:

while(read >> f >> l >> t >> s >> sta >> acct >> bal)
{
    cout << "test" << endl;
    ptr[i] = account(f,l,t,s,sta,acct,bal);
    ptr[i].printcontents();
    cout << "test" << endl;
    i++;
    cout << i << endl;
}

【讨论】:

  • 为了提供更多上下文,这应该是银行程序的一部分,其中我使用一组指针指向存储帐户信息(名称、帐号等)的帐户对象。最初,我声明了帐户 *ptr[10] 并尝试访问类帐户的成员函数(包括 account.h),例如 ptr[i]->setacctnum(acct);但这导致程序崩溃。我不明白为什么这不起作用,但这就是我现在所处的位置。
  • 声明 account *ptr[10] 会创建一个指向帐户对象的未初始化指针数组。这就是你的程序崩溃的原因:你试图在悬空指针上调用方法。您应该考虑避免使用指针并声明account ptr[10]:您将能够通过ptr[i].setacctnum(acct); 之类的调用访问成员函数(注意. 而不是-&gt;,因为ptr[i] 现在是一个对象而不是指针)。如果你真的需要指针,考虑std::unique_ptr
【解决方案2】:

每个new 都应该与delete 平衡

如果你有一个指针数组,并且每个指针都有new,那么你需要delete每个实例。

另一方面,如果您 new 一个对象数组,那么您可以 delete [] 整个数组。

顺便说一句,对于您的代码,不要使用ptr(您没有告诉我们详细信息,请考虑仅使用std::vector&lt;account&gt; 并使用push_back,然后它将根据需要自动调整大小,而不是ptr[i] = new...

【讨论】:

    【解决方案3】:

    通常您必须删除您创建的每个实例。具体怎么做取决于...但简单的经验法则:

    new 的每次使用都必须有delete 的使用。

    new[] 的每次使用都必须有delete[] 的使用。

    如果您从自动声明中获取实例,则无需执行任何操作,因为它将随堆栈帧一起被销毁;但如果你创造了它,你就会摧毁它。

    【讨论】:

      【解决方案4】:

      正如其他人所指出的,如果您使用new那么您将需要delete。但是,您真正的麻烦是概念上的。你问了一个很好的问题,newdelete 是外围的。

      在超过 99.5% 的情况下,析构函数的正常使用是让编译器自动调用它们。 (0.5% 的例外很深奥。我们现在不需要担心这个。)

      考虑这个代码片段:

        int n = 5;
        {
          int m = 2;
          ++m;
          n *= m;
          // The variable m is automatically destructed here.
        }
        // Here, n == 15.
      

      看看它是如何工作的? m 的析构函数在 m 达到其生命周期结束时自动调用,这(因为 m 不是用 new 创建的)发生在实例化 m 的块的末尾。

      当然,m 是一个int,所以它的析构函数不做任何事情(或者,如果您愿意,m 没有析构函数)。你自己定义的其他类型,比如你的类型account,可以有析构函数。当单个对象(account 的实例)达到其生命周期的尽头时,会自动针对单个对象调用析构函数。

      新建和删除

      那么,这与newdelete 有什么关系?

      在我的代码片段中,我没有使用new。因此,我的对象的生命周期由括号控制。

      在您的代码片段中,您确实使用了new。因此,对象的生命周期由您对delete 的使用控制。

      当然,你忘了使用delete,这就是为什么你的对象永远不会被破坏(除非你的整个程序退出时)。

      其他人已经注意到现代 C++ 提供了 new 的改进替代方案,您应该在大多数情况下使用它们。你可以阅读他们的答案。但是,从机制上讲,了解普通的 new 的作用以及 delete 如何与它配对仍然非常有帮助。

      手动调用析构函数

      您几乎可以肯定不必担心这一点,因为手动调用析构函数的情况很少见且很先进。基本上,如果您自己管理存储对象的内存(您几乎从不这样做,但也有极少数例外),那么编译器无法判断何时销毁,因此您必须告诉它何时销毁。请参阅 this 了解典型的深奥示例。

      【讨论】:

        【解决方案5】:

        只有指针需要调用析构函数来删除它们或关闭程序

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-07-24
          • 2012-06-25
          相关资源
          最近更新 更多