当局部变量超出其作用域时,析构函数是否总是能够被保证调用?

7

编译器可以进行很多优化(比如内联一些函数),我有点怀疑在我的程序中,所有为局部变量分配的内存是否在函数调用后都被清除了(基于OS X系统监视器的结果)。因此我想问:标准是否保证所有局部变量的析构函数会在它们超出作用域的那一刻被精确调用?


根据“cleared”,我认为您的意思是将对象释放回运行时。是的,析构函数会被调用。在这些析构函数中什么,完全取决于个人猜测。 - WhozCraig
在https://dev59.com/-13Ua4cB1Zd3GeqP8gEo#8047778中的引用: - Flexo
当你说“分配内存”时,如果它是由构造函数分配并由析构函数释放的,那么是的,分配的内存将被释放。 - brian beuning
你可以有一点怀疑,但我非常确定这样的错误会在很早的阶段被发现,远在编译器发布之前。 - Mr Lister
5个回答

12

是的。根据C++11标准第3.7.3段:

在块作用域中显式声明为register或未显式声明为staticextern的变量具有自动存储期这些实体的存储持续到创建它们的块退出为止

请注意,这仅涉及具有自动存储期的变量。如果您使用new动态创建对象并将结果分配给本地原始指针,则仅会销毁原始指针,而不是指向的对象:

{
    int* foo = new int(42);
} // Here you have a memory leak: the foo pointer is destroyed,
  // but not the object foo pointed to

非常重要的例子。感谢分享。 - mandy1339

7

是的,这是有保证的。

使用系统监视器来监控内存使用可能不太准确,因为应用程序不会将内存返回给系统。一旦分配,它就属于应用程序,即使您的对象被销毁,您也可能看不到任何区别。

如果您想保证您的应用程序没有内存泄漏,您可能需要使用诸如valgrind或Google的drMemory等工具,或者其他几个(搜索"memory leak detection")。在这种情况下,您将获得关于分配、释放、泄漏、内存访问违规等方面最精确的信息。


这就解释了为什么在系统监视器中我看不到足够的空闲内存!有没有办法将未使用的内存返回给操作系统,或者它完全由操作系统内存管理处理?我来解释一下我的情况:我的程序多次调用一个非常重的函数(该函数为内部使用分配了大量内存),从一个调用到另一个调用时,它的内存占用并不增加,但也不会在这些调用之间减少(至少在系统监视器中是如此)。 - lizarisk
@lizarisk: 我相信你无法将内存返回给系统。真的,试试使用valgrind或其他内存泄漏检测工具。它会向你展示内存泄漏发生的确切位置。 - nogard

3

每个超出作用域的变量都会保证调用其析构函数。

6.7 声明语句

2 具有自动存储期(3.7.3)的变量在其声明语句执行时每次都会被初始化。在块中声明的具有自动存储期的变量在退出该块时被销毁(6.6)。


1

如果您的代码类似于以下内容,它将会起作用:

void f()
{
  A a;  // create a local instance of A
        // memory will be allocated on the stack, 
        // and the constructor for `a` will be called.

  // various code here

  // here at the end of the scope, 
  // the destructor for `a` will be called,
  // and the memory on the stack will be freed.
}

1

是的,这种情况总会发生。C++语言保证了它。来自C++ FAQ lite:

[11.5] 我应该在局部变量上显式调用析构函数吗?

不需要!

析构函数将在创建局部变量的块的关闭}处再次调用。这是语言的保证;它会自动发生;无法阻止它发生。但是,如果在同一对象上第二次调用析构函数,可能会导致非常糟糕的结果!崩溃!你死定了!


虽然有些超出了你的问题,但基本原理是相同的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接