抛出的构造函数没有泄漏

Bia*_*sta 1 c++ memory-leaks

根据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;
}
Run Code Online (Sandbox Code Playgroud)

确实.结果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)
Run Code Online (Sandbox Code Playgroud)

该程序编译为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()
Run Code Online (Sandbox Code Playgroud)

动态分配发生在调用生成泄漏的构造函数之后.

Fir*_*ost 6

如果构造函数抛出异常,则内存不会泄漏,因为如果存在适当的释放函数,则分配器必须在传递异常之前释放内存.

根据2017年3月的工作草案:

8.3.4新[expr.new]

20如果new-expression创建一个对象或类类型的对象数组,则对分配函数,释放函数(15.5)和构造函数(15.1)进行访问和歧义控制.如果 new-expression创建了类类型的对象数组,则可能会调用析构函数(15.4).

21如果上面描述的对象初始化的任何部分80通过抛出异常终止并且可以找到合适的解除分配函数,则调用释放函数以释放构造对象的存储器,之后异常继续传播.新表达的背景. 如果找不到明确的匹配解除分配函数,则传播异常不会导致释放对象的内存.[注意:当被调用的分配函数不分配内存时,这是合适的; 否则,很可能导致内存泄漏. - 结束说明]

80)这可能包括评估新初始化程序和/或调用构造函数

另外,根据C++ wiki中Exceptions FAQ:

"但是从调用的构造函数中抛出异常new导致内存泄漏!"废话!这是一个由一个编译器中的错误引起的老太太的故事 - 这个错误在十年前就被立即修复了.