2013-03-09 57 views
6

C++标准抛出异常状态有关的std::call_once执行与抛出异常(§30.4.4.2/ 2)的功能如下:从标准:: call_once的

2 /效果:call_once的的执行那不称它的功能是被动执行。调用其func的call_once的执行是主动执行。主动执行应调用INVOKE(DECAY_- COPY(std :: forward(func)),DECAY_COPY(std :: forward(args))...)。 如果这样的func调用引发异常,则执行异常,否则返回。异常执行应将异常传播给call_once的调用者。在任何给定once_flag的call_once的所有执行中:最多一个应该是返回执行;如果有一个返回的执行,它应该是最后一次执行;只有在执行完成后才会被动执行。 [注意:被动执行允许其他线程可靠地观察先前返回执行产生的结果。 - 注完]

我使用Visual Studio 2012,并运行下面的代码:

void f(){ 
    throw std::exception("Catch me!"); 
} 

int main(int argc, char* argv[]){ 
    once_flag flag; 
    try{ 
     call_once(flag, f); 
    } catch(const std::exception& e){ 
     cout << e.what() << endl; 
    } 
    return 0; 
} 

我的结果是:在catch块中运行的代码,并打印消息,但是当程序存在我得到abort()呼叫并打印以下信息来清点:

... \ mutex.c(38)互斥破坏而忙碌

这是否应该发生?

+2

不,这是一个错误,程序应该可以正常工作(尽管你对'std :: exception'使用非标准的构造函数,在ISO C++中,你只能默认构造'std :: exception',频繁的可移植性问题,当MSVC用户检查incode是要在其他实现编译) – 2013-03-09 14:14:49

回答

7

这是应该发生的吗?

不,不是真的。这是一个错误

但是,请注意一个事实,即VC11并不孤单在这:

  • 英特尔ICC 13.0.1调用std::terminate()好像你的异常没有被处理(见live example);
  • GCC 4.8.0 beta可能做类似的事情,但它不显示任何输出,它只是吞下异常并以静默终止程序(请参阅live example)。 [UPDATE:此错误似乎并没有在其他enviroments重复性好,很可能是与liveworkspace.org仅配置的问题]

GCC 4.7.2和3.2锵,在另一方面,表现正确。

顺便说一句,值得注意的是C++标准(第18.8.1节)指定了std::exceptiononly has a default constructor and a copy constructor。您正在使用的构造函数最可能是不可移植的MS扩展。

您可以考虑使用std::logic_error相反,从std::exception派生并支持构造函数接受一个字符串。

+1

谢谢,我不知道std :: exception只有一个默认和复制构造函数,我实际上在原始代码中使用自定义异常。现在我不会抛出call_once的异常,谢谢澄清。 – 2013-03-09 15:18:49

+4

值得注意的是,当'call_once'返回一个异常时,它不被视为满足。即下次执行'call_once'时,将再次尝试'f'。依此类推,直到'f'返回而没有抛出异常。 – 2013-03-09 16:05:09

+0

@HowardHinnant:很好的观察,谢谢你提到。 – 2013-03-09 16:06:29