C++ 当对象超出范围时是否调用析构函数?

C++ 当对象超出范围时是否调用析构函数?,c++,destructor,dynamic-memory-allocation,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; } 编译器会隐式调用析构函数还是内存泄漏 我是动态内存新手,所以如果这不是一个可用的测试用例,我很抱歉。确实会有内存泄漏。会调用超出范围的对象(Foo*

例如:

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

    return 0;
}

class Foo {
private:
    somePointer* bar;

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

Foo::~Foo() {
    delete bar;
}
编译器会隐式调用析构函数还是内存泄漏


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

确实会有内存泄漏。会调用超出范围的对象(Foo*)的析构函数,但不会调用指向对象(分配的Foo)的析构函数

从技术上讲,由于您处于主状态,因此它不是内存泄漏,因为您可以在应用程序未终止之前访问每个分配的变量。在这方面,我引用Alexandrescu(从现代C++,关于单体的章节)

分配累积数据并丢失所有数据时,会出现内存泄漏 对它的引用。这里的情况并非如此:没有任何东西在积累, 我们将有关分配内存的知识保存到 应用此外,所有现代


当然,这并不意味着您不应该调用
delete
,因为这将是一种非常糟糕(而且危险)的做法。

在这种情况下,当main返回程序结束时,操作系统将处理释放所有资源的问题。例如,如果这是任何其他函数,则必须
使用delete。

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

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


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

首先注意,代码不会编译
new
返回指向堆上分配的对象的指针。你需要:

int main() {
    Foo *leedle = new Foo();
    return 0;
}

现在,由于
new
使用动态存储而不是自动分配对象,因此在函数结束时它不会超出范围。因此,它也不会被删除,并且您已经泄漏了内存。

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

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

Foo的析构函数会在main()的末尾被调用吗

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

请注意自动变量是什么:

Foo* leedle = new Foo();
这里,
leedle
是将被销毁的自动变量
leedle
只是一个指针。
leedle
指向的东西没有自动存储持续时间,不会被销毁。因此,如果您这样做:

void DoIt()
{
  Foo* leedle = new leedle;
}
您泄漏了
new leedle
分配的内存


必须
删除
已分配给
新的
的任何内容:

void DoIt()
{
  Foo* leedle = new leedle;
  delete leedle;
}

通过使用智能指针,这变得更加简单和健壮。在C++03中:

void DoIt()
{
  std::auto_ptr <Foo> leedle (new Foo);
}
在本例中,所有变量都具有自动存储持续时间。
b
d
都将在第2行销毁<代码>n将在第1行销毁

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

3:动态:使用动态内存分配功能(例如,
新建
)分配时,将分配具有动态存储持续时间的变量;使用动态内存分配功能(例如,
删除
)销毁时,将销毁该变量

在我上面的原始示例中:

void DoIt()
{
  Foo* leedle = new leedle;
}
leedle
是一个具有自动存储持续时间的变量,将在末尾销毁。
leedle
指向的对象具有动态存储持续时间,并且不会在上面的代码中被销毁。您必须调用
delete
来取消分配它

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


4:线程:线程开始时分配具有线程存储持续时间的变量,线程结束时解除分配。

否,您需要自己调用
delete leedle
。标题中的问题为“是”,正文中的问题为“否”。您必须手动删除所有新增内容。如果在构造函数中使用
new
(前提是没有引发异常),则可以在析构函数中调用
delete
,它将为您清理内存。您的代码甚至无效。请阅读一本C++书——这是一个基本问题,在很多时候都是这样。阅读一些关于RAII的信息,使用智能指针(SyddypTR,UnqyGypTR等等)。可能的副本可能会有点复杂。抱歉,我在写文章的时候错误地提交了,但是你不能仅仅依靠OS来为你做所有的工作。1.向明显的新手传授不良做法。另外,C++标准并不保证OS会回收资源,或者OS甚至存在。即使这样,OS也可能只是简单地调用调用析构函数来恢复内存。保证OS将释放所有内存,但是,这不是当前问题的主题。如果一个在GPU和操作系统上拥有资源的对象刚刚回收了内存,因为它不能保证它会调用任何析构函数,甚至不知道它们的存在,那么vidmem中将发生内存泄漏。请停止使用outmod
void Foo()
{
  bool b = true;
  {
    int n = 42;
  } // LINE 1
  double d = 3.14;
} // LINE 2
void DoIt()
{
  Foo* leedle = new leedle;
}