为什么在对象构造函数中抛出新表达式时不调用释放函数?

Why deallocation function is not called when object constructor throw in a new expression?

如果我按如下方式定义 operator delete,并且如果对象构造函数抛出新表达式,我希望看到调用已定义的 operator delete 的结果:

#include <new>
#include <cstdlib>
#include <iostream>

void*
operator new(std::size_t s){
  std::cout << "alloc " << std::endl;
return std::malloc(s);
}

void
operator delete(void* p) noexcept {
  std::cout << "dealloc " << std::endl;
  std::free(p);
}
void
operator delete(void* p,std::size_t) noexcept{
    std::free(p);
    std::cout << "dealloc s" << std::endl;
}

struct A{
  A(int i){
     if(i>0)
       throw 10;
  }
};

int main(int argc// will equal 10
        ,char* arg[])
{
  for(int i=0;i<argc;++i)
     auto p=new A{argc};
  return 0;
}

这个程序只输出alloc,为什么没有调用operator delete?在标准 [expr.new] 中指定:

If any part of the object initialization described above terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed, after which the exception continues to propagate in the context of the new-expression.

如果您修复代码以抛出异常,它会按预期工作:

int main(int argc,char* arg[])
{
    try {
        new A(2);
    }
    catch (...)
    {}
}

Demo

如果在构造过程中使用new,构造函数抛出异常,C++运行时库:

  1. 如果找不到合适的捕获处理程序,则调用 std::terminate()。是否调用 delete 是实现定义的。

  1. 在 "sending" 之前为您调用 delete 如果找到合适的 catch 处理程序的异常,尽管未调用析构函数 - 即 ~A(),如果您有一个,当 i 大于 1 时不会被调用。

正如其他人已经指出的那样,这是因为您没有捕获异常。作为标准说明:

C++11 §15.3/9:
“If no matching handler is found, the function std::terminate() is called; whether or not the stack is unwound before this call to std::terminate() is implementation-defined.”

虽然我认为这与您的情况下的堆栈没有具体关系,但同样的原则也适用于此。因此,是否清理任何内存实际上取决于实现。正如我们在这里看到的,通常情况并非如此,因为操作系统无论如何都会清理内存。