【问题标题】:Why deallocation function is not called when object constructor throw in a new expression?为什么当对象构造函数抛出新表达式时不调用释放函数?
【发布时间】:2018-02-10 06:01:59
【问题描述】:

如果我将 operator delete 定义如下,并且如果对象构造函数抛出 new 表达式,我希望看到调用定义的 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,为什么没有调用操作符delete?在标准 [expr.new] 中规定:

如果上述对象初始化的任何部分通过抛出异常和合适的 可以发现deallocation函数,调用deallocation函数释放对象所在的内存 正在构造,之后异常继续在 new-expression 的上下文中传播。

【问题讨论】:

  • 你没有 try catch 块。
  • @Jarod42 你是对的!谢谢!我需要 catch 块,因为存在异常的主要功能是 UB 还是出于其他先前的原因?
  • 用于UB部分。顺便说一句,return i; 无效(i 超出范围)。
  • @Jarod42:这不是 UB。当未捕获到异常时,调用 std::terminate。
  • argc 的值是多少?我想是 1,所以你不会抛出异常。

标签: c++ new-operator dynamic-memory-allocation delete-operator


【解决方案1】:

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

C++11 §15.3/9
“如果没有找到匹配的处理程序,则调用函数std::terminate();在此调用 std::terminate() 之前是否展开堆栈是实现定义的。”

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

【讨论】:

  • 我对您的帖子很感兴趣,因为您回答了“为什么?”。我认为这里不涉及内存清理。实现必须确保实际发生可见的副作用(内存清理可能不被视为副作用)。 I/O 是一个可见的副作用。因此,Clang 和 GCC 可能已经将内存释放作为堆栈展开过程的一部分实现,标准中没有任何内容禁止这样做,并且在 GCC 文档中,指定终止不执行堆栈展开。谢谢我现在明白了!
【解决方案2】:

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

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

Demo

【讨论】:

    【解决方案3】:

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

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

    1. 调用delete 之前为您“发送”该异常到合适的catch 处理程序(如果找到),虽然没有调用析构函数- 即~A(),如果你有一个,当i 时不会被调用大于 1。

    【讨论】:

    • 我认为这不适用于这里:如果捕获异常,则调用定义的删除运算符,而如果没有捕获则不会调用它。所以你的“在给你那个例外之前”是非常模棱两可的。
    • @koalo 是的,我已经对这个答案做了正确的猪耳朵。我已经修改了。
    猜你喜欢
    • 1970-01-01
    • 2014-01-28
    • 2023-03-19
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 2017-10-10
    • 2019-11-16
    • 2012-03-16
    相关资源
    最近更新 更多