当一个对象超出范围时,是否会调用析构函数?

Tux*_*Tux 37 c++ destructor dynamic-memory-allocation

例如:

int main() {
    Foo *leedle = new Foo();

    return 0;
}

class Foo {
private:
    somePointer* bar;

public:
    Foo();
    ~Foo();
};

Foo::~Foo() {
    delete bar;
}
Run Code Online (Sandbox Code Playgroud)

析构函数会被编译器隐式调用还是会出现内存泄漏?

我是动态内存的新手,所以如果这不是一个可用的测试用例,我很抱歉.

Joh*_*ing 92

是的,自动变量将在封闭代码块的末尾被销毁.但继续阅读.

你的问题标题询问当变量超出范围时是否会调用析构函数.大概你要问的是:

将在main()结束时调用Foo的析构函数吗?

鉴于您提供的代码,该问题的答案是否定的,因为Foo对象具有动态存储持续时间,我们将很快看到.

请注意自动变量是什么:

Foo* leedle = new Foo();
Run Code Online (Sandbox Code Playgroud)

这里leedle是要销毁的自动变量. leedle只是一个指针.leedle指向的东西没有自动存储持续时间,也不会被销毁.所以,如果你这样做:

void DoIt()
{
  Foo* leedle = new leedle;
}
Run Code Online (Sandbox Code Playgroud)

泄漏分配的内存new leedle.


必须 delete分配任何东西new:

void DoIt()
{
  Foo* leedle = new leedle;
  delete leedle;
}
Run Code Online (Sandbox Code Playgroud)

通过使用智能指针,这变得更加简单和强大.在C++ 03中:

void DoIt()
{
  std::auto_ptr <Foo> leedle (new Foo);
}
Run Code Online (Sandbox Code Playgroud)

或者在C++ 11中:

void DoIt()
{
  std::unique_ptr <Foo> leedle = std::make_unique <Foo> ();
}
Run Code Online (Sandbox Code Playgroud)

智能指针用作自动变量,如上所述,当它们超出范围并被销毁时,它们会自动(在析构函数中)delete指向的对象.因此,在上述两种情况下,都没有内存泄漏.


我们试着在这里澄清一点语言.在C++中,变量具有存储持续时间.在C++ 03中,有3个存储持续时间:

1:自动:具有自动存储持续时间的变量将在封闭代码块的末尾被销毁.

考虑:

void Foo()
{
  bool b = true;
  {
    int n = 42;
  } // LINE 1
  double d = 3.14;
} // LINE 2
Run Code Online (Sandbox Code Playgroud)

在此示例中,所有变量都具有自动存储持续时间.两个b并将d在第2 n行销毁. 将在第1行销毁.

2:static:具有静态存储持续时间的变量将在程序开始之前分配,并在程序结束时销毁.

3:动态:当您使用动态内存分配函数(例如new)分配动态存储持续时间时,将分配具有动态存储持续时间的变量,并在使用动态内存分配函数(例如)销毁它时将其销毁delete.

在我上面的原始示例中:

void DoIt()
{
  Foo* leedle = new leedle;
}
Run Code Online (Sandbox Code Playgroud)

leedle是一个具有自动存储持续时间的变量,将在末端括号中销毁.该事leedle指向具有动态存储持续时间和代码不被破坏的上方.你必须打电话delete取消分配它.

C++ 11还增加了第四个存储持续时间:

4:thread:线程存储持续时间的变量在线程开始时分配,并在线程结束时解除分配.

  • 很好的答案 - 在继续讨论[动态]间接对象的语义之前,我首先指出[自动]指针_will_被销毁,我发现这个主题非常有效.随着Eric的纠正,这个答案是完美的. (2认同)

Arn*_*rtz 7

是的,如果一个对象超出范围,则会调用析构函数.但是 ,在这种情况下不会调用析构函数,因为你只有一个指针在范围内,该指针没有特定的析构函数,因此不会间接调用Foo析构函数.

这个例子是像std::unique_ptr和的智能指针的应用领域std::shared_ptr.这些是实际的类,与原始指针不同,它一个析构函数,(有条件地)调用delete指向的对象.

顺便说一句,Foo析构函数删除bar,bur bar从未被初始化,也没有分配给指向实际对象的地址,因此删除调用将给出未定义的行为,可能是崩溃.