1

如果在一个函数中,我新建了一个对象,我应该在函数退出之前在指针上调用 delete 还是在函数退出后自动调用的析构函数完成删除的工作?

例如,

   void f()
   {
     A * a = new A(); // assume A has destructor defined, which frees any dynamically assigned resources
   }


 OR

  void f()
  {
    A * a = new A();
    delete a;
  }

删除和自动调用析构函数是否等效?

4

5 回答 5

12

如果在一个函数中,我新建了一个对象,我应该在函数退出之前在指针上调用 delete 还是在函数退出后自动调用的析构函数完成删除的工作?

从函数返回时,所有具有自动存储持续时间的本地对象都被销毁。如果它们属于类类型,则在收回它们占用的存储空间之前调用它们的析构函数。如果它们是非类类型(如int),则无需调用析构函数。

这里,唯一具有自动存储持续时间的本地对象是指针a(注意:不是a! 指向的对象),并且指针不是类类型。这意味着a将被销毁,仅此而已 - 特别是,a 指向的对象不会被销毁。

因此,您必须delete在离开函数之前调用(无论您是通过执行return还是通过抛出异常离开它)。通常,您必须始终将每个呼叫new与呼叫匹配delete,并将每个呼叫new[]与呼叫匹配delete[]

由于deletenew使用 .是本地对象,其析构函数旨在清理在构造过程中获得的资源。

例如:

void foo()
{
    auto p = std::make_unique<A>(); // OK, make_unique() will only be available
                                    // in C++14. Meanwhile, in C++11 you can do:
                                    //
                                    // std::unique_ptr<A> p(new A());

    // Work with p...

    // No memory leak here!
}

如果您不允许使用 C++11,例如因为您的老板说出于兼容性原因必须在旧版本的编译器上编译 SW,您总是可以使用Boost 的智能指针类(例如boost::shared_ptrboost::scoped_ptr.

无论如何,请注意,除非需要,否则不应执行动态分配。如果您不需要它(例如,如果您不必与任何其他函数共享该对象的所有权),您可以简单地为您的A对象提供自动存储持续时间,从而确保在超出范围时调用其析构函数:

void foo()
{
    A a;

    // Work with a...

    // a will be destroyed when returning from foo()
}
于 2013-06-20T13:52:52.833 回答
3

只有自动对象超出范围时才会被销毁:

void f() {
    A a;
} // destroyed here

如果你用 动态分配一个对象new,那么你有责任用delete;来释放它。否则,它将永远保持分配状态,您将泄漏内存。这可能很难正确管理,尤其是在异常可能导致您离开指针范围的情况下。

new出于这个原因,除非你真的需要,否则不要使用;并始终使用共享指针或其他RAII对象为您管理动态对象。

于 2013-06-20T13:51:43.767 回答
1

唯一将被释放的是指针变量本身(因为它也需要内存来存储它指向的地址,并且它的范围仅在函数体中)。指针指向的对象完全由您负责,因此您应该在显式分配它时显式删除它。

于 2013-06-20T13:50:20.963 回答
1

当您动态分配内存时,当变量超出范围时它不会被释放。您将不得不明确delete表示该内存。

于 2013-06-20T13:50:23.337 回答
0

我将从这个开始,

什么时候调用构造函数?

当一个对象被创建(构造)时。 MyClass c,d(1);等等

构造函数用于在使用对象之前正确初始化对象。分配必要的动态内存等。

什么时候调用析构函数?

当对象超出范围时(遇到}声明对象的大括号时)。当您的对象超出范围时,会自动调用析构函数。

当您动态分配内存(new)时,它会一直存在,直到您明确释放(delete)它。还有什么比构造函数更能确保你想要发生的事情。因为,在对象被销毁之前保证会调用一个析构函数,你可以调用delete它。

默认情况下,析构函数不会做任何事情来清除您可能在代码中创建的副作用。它不会为你释放内存。

你知道你的管家会跟着你走出房间。并且只会做你要求他做的事情。如果你指示他,他会在你离开后清理你的桌子。如果你不指示他这样做,你必须确保你在某个地方自己做,或者只是把烂摊子抛在脑后

于 2013-06-20T14:06:44.973 回答