抛出的构造函数

时间:2018-02-20 22:51:15

标签: 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;
}

事实上。 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()

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

1 个答案:

答案 0 :(得分:6)

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

根据March 2017 Working Draft

  

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调用的构造函数中抛出异常会导致内存泄漏!”废话!这是一个由一个编译器中的错误引起的老太太的故事 - 这个错误在十年前就被立即修复了。