处理异常时内存泄漏
Memory leak while handling exceptions
我刚从 C 转到 C++,目前正在通过异常切分我的路径。
我很难弄明白为什么我会在这个简单的程序中发生内存泄漏:
#include <iostream> /* I/O */
#include <exception> /* exception */
#include <cstdlib> /* stdlib */
using namespace std;
void Bar()
{
throw exception();
}
void Foo()
{
int *ip = new int;
try
{
Bar();
}
catch(exception &e)
{
cerr << "Foo: Exception caught: " << e.what() << endl;
delete ip;
exit(1);
}
delete ip;
}
int main()
{
Foo();
return 0;
}
我觉得我在这里遗漏了一些重要的东西,但无法指出它。有什么想法吗?
Valgrind 的输出:
==21857== Memcheck, a memory error detector
==21857== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21857== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==21857== Command: ./a.out
==21857==
Foo: Exception caught: std::exception
==21857==
==21857== HEAP SUMMARY:
==21857== in use at exit: 136 bytes in 1 blocks
==21857== total heap usage: 3 allocs, 2 frees, 72,844 bytes allocated
==21857==
==21857== 136 bytes in 1 blocks are possibly lost in loss record 1 of 1
==21857== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21857== by 0x4ECD8FF: __cxa_allocate_exception (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==21857== by 0x108CCC: Bar() (ex33.cpp:9)
==21857== by 0x108D0C: Foo() (ex33.cpp:18)
==21857== by 0x108DBD: main (ex33.cpp:31)
==21857==
==21857== LEAK SUMMARY:
==21857== definitely lost: 0 bytes in 0 blocks
==21857== indirectly lost: 0 bytes in 0 blocks
==21857== possibly lost: 136 bytes in 1 blocks
==21857== still reachable: 0 bytes in 0 blocks
==21857== suppressed: 0 bytes in 0 blocks
==21857==
==21857== For counts of detected and suppressed errors, rerun with: -v
==21857== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
事实证明,将 Foo()
中的 exit(1)
替换为 return;
修复了内存泄漏。
所以,我的后续问题,为什么我不能从 Foo()
调用 exit()
?
你真的不应该在 C++ 中调用 exit。不会调用本地对象的析构函数。而且因为栈不会被unwounded,貌似异常的析构函数也不会被调用。
来自标准:
18.1.2 When an exception is thrown, control is transferred to the nearest handler with a matching type (18.3); “nearest” means the
handler for which the compound-statement or ctor-initializer following
the try keyword was most recently entered by the thread of control and
not yet exited
18.1.3 Throwing an exception copy-initializes (11.6, 15.8) a temporary object, called the exception object. An lvalue denoting the temporary
is used to initialize the variable declared in the matching handler
(18.3). If the type of the exception object would be an incomplete
type or a pointer to an incomplete type other than cv void the program
is ill-formed.
堆栈未展开:不调用具有自动存储持续时间的变量的析构函数。引用自 here
我刚从 C 转到 C++,目前正在通过异常切分我的路径。
我很难弄明白为什么我会在这个简单的程序中发生内存泄漏:
#include <iostream> /* I/O */
#include <exception> /* exception */
#include <cstdlib> /* stdlib */
using namespace std;
void Bar()
{
throw exception();
}
void Foo()
{
int *ip = new int;
try
{
Bar();
}
catch(exception &e)
{
cerr << "Foo: Exception caught: " << e.what() << endl;
delete ip;
exit(1);
}
delete ip;
}
int main()
{
Foo();
return 0;
}
我觉得我在这里遗漏了一些重要的东西,但无法指出它。有什么想法吗?
Valgrind 的输出:
==21857== Memcheck, a memory error detector
==21857== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==21857== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==21857== Command: ./a.out
==21857==
Foo: Exception caught: std::exception
==21857==
==21857== HEAP SUMMARY:
==21857== in use at exit: 136 bytes in 1 blocks
==21857== total heap usage: 3 allocs, 2 frees, 72,844 bytes allocated
==21857==
==21857== 136 bytes in 1 blocks are possibly lost in loss record 1 of 1
==21857== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21857== by 0x4ECD8FF: __cxa_allocate_exception (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.25)
==21857== by 0x108CCC: Bar() (ex33.cpp:9)
==21857== by 0x108D0C: Foo() (ex33.cpp:18)
==21857== by 0x108DBD: main (ex33.cpp:31)
==21857==
==21857== LEAK SUMMARY:
==21857== definitely lost: 0 bytes in 0 blocks
==21857== indirectly lost: 0 bytes in 0 blocks
==21857== possibly lost: 136 bytes in 1 blocks
==21857== still reachable: 0 bytes in 0 blocks
==21857== suppressed: 0 bytes in 0 blocks
==21857==
==21857== For counts of detected and suppressed errors, rerun with: -v
==21857== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
事实证明,将 Foo()
中的 exit(1)
替换为 return;
修复了内存泄漏。
所以,我的后续问题,为什么我不能从 Foo()
调用 exit()
?
你真的不应该在 C++ 中调用 exit。不会调用本地对象的析构函数。而且因为栈不会被unwounded,貌似异常的析构函数也不会被调用。
来自标准:
18.1.2 When an exception is thrown, control is transferred to the nearest handler with a matching type (18.3); “nearest” means the handler for which the compound-statement or ctor-initializer following the try keyword was most recently entered by the thread of control and not yet exited
18.1.3 Throwing an exception copy-initializes (11.6, 15.8) a temporary object, called the exception object. An lvalue denoting the temporary is used to initialize the variable declared in the matching handler (18.3). If the type of the exception object would be an incomplete type or a pointer to an incomplete type other than cv void the program is ill-formed.
堆栈未展开:不调用具有自动存储持续时间的变量的析构函数。引用自 here