【发布时间】:2014-01-01 20:07:43
【问题描述】:
当抛出异常时,抛出异常的块从堆栈中展开:
int main ()
{
try
{
Object x; // doesn't throw
Object y; // throws
cout << "wonderful";
}
catch (...)
{
cout << "fail";
}
}
当Object在堆上分配构造内存并在销毁时正确释放它,那么应该没有内存泄漏,因为堆栈展开调用x的析构函数(不是y,但Object保证,当构造函数失败时,没有内存泄漏)。就目前而言,不是吗?
让我们深入探讨:
int main ()
{
Object x; // doesn't throw
double *d = new double[256*256*256]; // doesn't throw
Object y; // throws
cout << "wonderful";
delete[] d;
}
由于受过良好的教育,我想自己清理垃圾,而不是让操作系统来做。我知道,每个现代操作系统都会自行删除程序的堆内存,该程序会意外终止(或预期,但没有显式释放)。所以在大写的情况下,d 的释放会执行我的操作系统,但x 仍会正确释放其内存(因为堆栈展开和析构函数调用)之前操作系统会这样做,对吧?
那又怎样:
#include <cstdlib>
int main ()
{
Object x; // doesn't throw
try { Object y; } // throws
catch (...) { cout << "fail"; exit(EXIT_FAILURE); }
cout << "working and working...";
cin.get();
}
x 的析构函数是否被调用之前 exit 将控制权交还给操作系统?
更深入:
void Object::be_stupid ()
{
Object a; // doesn't throw
try { Object b; }// throws
catch (...) { exit(EXIT_FAILURE); }
}
void main ()
{
Object x; // doesn't throw
try { x.be_stupid(); } // exits program
}
x 的构造函数是否调用了 before exit 将控制权交还给操作系统?如果是,那么exit“展开”所有周围的堆栈,包括main(),对吗?
【问题讨论】:
-
exit 不会像异常抛出那样展开。但是,正如您所说的那样,您的程序即将死去,它真的不需要。其他“立即死亡”函数也是如此,例如 std::terminate。
-
@polkadotcadaver:虽然资源被操作系统清理,但仍然需要销毁对象,例如,刷新缓冲流。但是,
exit()确实没有进行任何本地清理(它仍然清理全局对象)。 -
@DietmarKühl 我同意 - 总是更好地优雅地处理清理,尤其是在使用 RAII 比 new/delete 更具想象力的情况下。
-
您可以查看this answer。它详细解释了 throws 如何导致内存泄漏。
-
@mb84 将 main 声明为 int main() 而不是退出只是返回,然后一切都会像离开任何函数时一样被清理,程序也会退出并清理静态对象.
标签: c++ exception heap-memory exit stack-unwinding