根据valgrind
,以下代码不包含内存泄漏:
#include <memory>
#include <stdexcept>
namespace {
class Foo {
public:
Foo();
};
Foo::Foo() { throw std::runtime_error("This is an error"); }
} // anonymous namespace
int main(int argc, char* argv[]) {
try {
new Foo();
} catch (const std::exception& aError) {
return -1;
}
return 0;
}
事实上。 valgrind --leak-check=full
的结果是:
==25913== Memcheck, a memory error detector
==25913== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==25913== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==25913== Command: ./test
==25913==
==25913==
==25913== HEAP SUMMARY:
==25913== in use at exit: 0 bytes in 0 blocks
==25913== total heap usage: 4 allocs, 4 frees, 72,890 bytes allocated
==25913==
==25913== All heap blocks were freed -- no leaks are possible
==25913==
==25913== For counts of detected and suppressed errors, rerun with: -v
==25913== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
该程序使用g++ (GCC) 7.3.0
编译。
注意:即使clang 5.0.1
也没有泄露。
注意:我检查了反汇编代码并且delete
有电话。
我的问题:为什么这段代码不会产生内存泄漏?它是否真的在标准中指定(可以链接吗?)或只是自主编译器增强?
我的期望:
...
call operator new(unsigned long)
mov rbx, rax
mov rdi, rbx
call (anonymous namespace)::Foo::Foo()
动态分配发生在调用生成泄漏的构造函数之后。
答案 0 :(得分:6)
如果构造函数抛出异常,内存不会泄漏,因为如果有适当的释放函数,分配器必须在传递异常之前释放内存。
8.3.4新[expr.new]
20如果 new-expression 创建一个对象或类类型的对象数组,访问和歧义控制 完成分配函数,释放函数(15.5)和构造函数(15.1)。如果 new-expression 创建一个类类型的对象数组,可能会调用析构函数(15.4)。
21如果上面描述的对象初始化的任何部分 80 通过抛出异常和合适的终止来终止 可以找到deallocation函数,调用deallocation函数来释放内存其中的对象 正在构建,之后异常继续在新表达的上下文中传播。 如果找不到明确的匹配解除分配函数,则不会传播异常 要释放的对象的内存。 [注意:当被调用的分配函数没有时,这是合适的 分配记忆;否则,很可能导致内存泄漏。 - 结束说明]
80)这可能包括评估 new-initializer 和/或调用构造函数
另外,根据Exceptions FAQ in the C++ wiki:
“但是从
new
调用的构造函数中抛出异常会导致内存泄漏!”废话!这是一个由一个编译器中的错误引起的老太太的故事 - 这个错误在十年前就被立即修复了。