C ++ 11中的范围(失败)?

时间:2012-10-21 20:19:04

标签: c++ exception c++11 destructor

我写了一个非常简单的解决方案但是有人笑了,发现了这里显示的缺陷http://ideone.com/IcWMEf

#include <iostream>
#include <ostream>
#include <functional>
#include <exception>
using namespace std;

// Wrong scope(failure)
class FailBlockT
{
    typedef function<void()> T;
    public:
    T t;
    FailBlockT(T t)
    {
        this->t=t;
    }
    ~FailBlockT()
    {
        if (std::uncaught_exception())
        {
            t();
        }
    }
};

struct Test
{
    ~Test()
    {
        try
        {
            FailBlockT f([]()
            {
                cout << "failure" << endl;
            });
            // there is no any exception here, but "failure" is printed.
            // See output below
        }
        catch(...)
        {
            cout << "some exception" << endl;
        }
    }
};

int main()
{
    try
    {
        Test t;
        throw 1;
    }
    catch(int){}
    return 0;
}

简而言之,问题是我的代码看std::uncaught_exception()。抛出异常并执行正常的析构函数时。如果我在那里使用范围失败,它会查看std::uncaught_exception()并认为对象范围因异常而丢失而不是简单地走出范围。

我想不出任何好的解决方案区分离开范围正常VS有一个异常抛出它。是的我知道投掷在dtors中是一个坏主意,但这就是为什么我没有注意到这个问题,因为我从不抛出异常。

我如何区分/解决这个问题?

2 个答案:

答案 0 :(得分:4)

  

我想不出任何好的解决方案来区分离开范围通常VS有一个异常抛出它。

检查stack_unwinding library - 我在C ++中实现了范围(失败)和范围(成功)功能。

它基于平台特定功能uncaught_exception_count。它类似于标准库中的std :: uncaught_exception,但它不是boolean结果,而是返回unsigned int,显示未捕获异常的当前计数。

目前,它已在{Clang 3.2,GCC 3.4.6,GCC 4.1.2,GCC 4.4.6,GCC 4.4.7,MSVC2005SP1,MSVC2008SP1,MSVC2010SP1,MSVC2012} x {x32,x64}进行测试。

在C ++ 11中,下面的语法是available

try
{
    int some_var=1;
    cout << "Case #1: stack unwinding" << endl;
    scope(exit)
    {
        cout << "exit " << some_var << endl;
        ++some_var;
    };
    scope(failure)
    {
        cout << "failure " << some_var << endl;
        ++some_var;
    };
    scope(success)
    {
        cout << "success " << some_var << endl;
        ++some_var;
    };
    throw 1;
} catch(int){}
{
    int some_var=1;
    cout << "Case #2: normal exit" << endl;
    scope(exit)
    {
        cout << "exit " << some_var << endl;
        ++some_var;
    };
    scope(failure)
    {
        cout << "failure " << some_var << endl;
        ++some_var;
    };
    scope(success)
    {
        cout << "success " << some_var << endl;
        ++some_var;
    };
}

在C ++ 98中,它有点noisier

try
{
    cout << "Case #1: stack unwinding" << endl;
    BOOST_SCOPE_EXIT(void) { cout << "exit" << endl; } BOOST_SCOPE_EXIT_END
    SCOPE_FAILURE(void) { cout << "failure" << endl; } SCOPE_FAILURE_END
    SCOPE_SUCCESS(void) { cout << "success" << endl; } SCOPE_SUCCESS_END
    throw 1;
} catch(int){}
{
    cout << "Case #2: normal exit" << endl;
    BOOST_SCOPE_EXIT(void) { cout << "exit" << endl; } BOOST_SCOPE_EXIT_END
    SCOPE_FAILURE(void) { cout << "failure" << endl; } SCOPE_FAILURE_END
    SCOPE_SUCCESS(void) { cout << "success" << endl; } SCOPE_SUCCESS_END
}

此外,库具有UNWINDING_AWARE_DESTRUCTOR功能。 Example

struct DestructorInClass
{
    UNWINDING_AWARE_DESTRUCTOR(DestructorInClass,unwinding)
    {
        cout << "DestructorInClass, unwinding: "
             << ( unwinding ? "true" : "false" ) << endl;
    }
};

但是,在某些情况下UNWINDING_AWARE_DESTRUCTOR可能give wrong results(虽然范围(成功)和范围(失败)功能不受此类问题的影响)。

答案 1 :(得分:3)

  

没有抛出异常,但它认为它有。

抛出 的异常,只是不是来自那里

C ++中没有任何一种机制可以问:“是否从我下面的代码抛出异常,但不是来自调用堆栈中的其他代码?” std::uncaught_exception正在完成它应该做的事情:说明当代码运行时是否正在进行异常。还有。

如果你想区分范围的异常退出并且只是简单地退出范围,那么你将不得不像其他人一样咬住子弹并捕获异常。

或者只是不要将此FailBlock内容放在析构函数中。在我看来,那些应该直接进入实际抛出的常规函数​​(并且析构函数永远不应该抛出)。在我看来,你担心一个没有任何意义的角落案件。