5

如果我定义的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,为什么运营商删除不叫?在标准的[expr.new]它被指定的是:

如果上述对象初始化的任何部分通过抛出异常和合适 释放函数可以发现终止,解除分配函数被调用,以自由其中正在构造对象 的内存,之后异常继续在新表达式的上下文中传播。

+0

您没有try catch块。 – Jarod42

+0

@ Jarod42你是对的!谢谢!我需要catch catch,因为生活的主要功能是UB,还是出于其他原因? – Oliv

+0

这是UB部分。顺便说一句,'return i;'是无效的('i'超出了范围)。 – Jarod42

回答

1

如果你解决你的代码抛出异常,它按预期工作:

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

Demo

1

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

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

  • 呼叫delete你之前如果发现,虽然析构函数不叫“发送”该异常到合适的catch处理 - 即~A(),如果你有一个,当i大于1时不会被调用。
  • +0

    我不认为这适用于这里:如果你捕获异常,定义的删除操作符IS被调用,而如果没有捕获,它不会被调用。所以你的“在给你这个例外之前”是非常含糊的。 – koalo

    +0

    @koalo是的,我已经做出了正确的答案。我修改了。 – Bathsheba

    2

    正如其他人已经提到的那样,这是因为你没有发现异常。作为标准的注释:

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

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

    +0

    我对你的文章感兴趣,因为你回答“为什么?”。我不认为这里涉及内存清理。实现必须确保实际发生可见的副作用(内存清理可能不被视为副作用)。 I/O是一种可见的副作用。所以Clang和GCC可能已经实现了内存释放作为堆栈展开过程的一部分,标准中没有任何内容禁止这一点,并且在GCC文档中,指定了终止不执行堆栈展开。谢谢,我明白了! – Oliv

    相关问题