6

C++ 标准规定了以下关于std::call_once抛出异常的函数的执行(第 30.4.4.2/2 节):

2/ 效果:不调用其函数的 call_once 执行是被动执行。调用其函数的 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()并将以下消息打印到 cout:

...\mutex.c(38) 互斥量在忙时被破坏

这应该发生吗?

4

1 回答 1

7

这应该发生吗?

不,不是。这是一个错误

但是,请注意 VC11 并不孤单:

  • 英特尔 ICC 13.0.1 调用std::terminate(),就好像您的异常没有被处理一样(参见实时示例);
  • GCC 4.8.0 beta 可能会做类似的事情,但它没有显示任何输出,它只是吞下异常并默默地终止程序(参见live example)。[更新:此错误似乎在其他环境中无法重现,并且可能仅是 liveworkspace.org 上的配置问题]

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

顺便说一句,值得注意的是 C++ 标准(第 18.8.1 段)指定std::exception 只有一个默认构造函数和一个复制构造函数。您使用的构造函数很可能是不可移植的 MS 扩展。

您可以考虑std::logic_error改用,它派生自std::exception并支持接受字符串的构造函数。

于 2013-03-09T14:30:54.317 回答