使用std :: make_exception_ptr的奇怪行为

时间:2015-08-10 17:50:59

标签: c++ c++11 exception-handling

我想知道为什么std::current_exception()在这种情况下的工作方式不同:

std::exception_ptr e, e2;
try {
    std::string("abcd").substr(42);
} catch(std::exception &ex) {
    std::cerr << "(1) Exception: " << ex.what() << std::endl;
    e = std::current_exception();
    e2 = std::make_exception_ptr(ex);
}
handle_exception(e);
handle_exception(e2);

而handle_exception打印异常:

void handle_exception(std::exception_ptr e)
{
    try {
        if (e)
            std::rethrow_exception(e);
    } catch(const std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
    }
}

输出如下:

(1) Exception: basic_string::substr: __pos (which is 42) > this->size() (which is 4)
(2) Exception: basic_string::substr: __pos (which is 42) > this->size() (which is 4)
(3) Exception: std::exception

但是我希望得到以下结果:

(1) Exception: basic_string::substr: __pos (which is 42) > this->size() (which is 4)
(2) Exception: basic_string::substr: __pos (which is 42) > this->size() (which is 4)
(3) Exception: basic_string::substr: __pos (which is 42) > this->size() (which is 4)

我在这里缺少什么?

2 个答案:

答案 0 :(得分:3)

std::make_exception_ptr()按值计算其参数。这意味着复制或就地构造。

你正在复制std :: exception(即切片)

答案 1 :(得分:1)

关于C ++ throw

请务必注意,C ++ throw(我将仅讨论其与操作数的用法,例如throw someExpression;)。对所传递的操作数的类型很敏感。它复制其操作数(从中复制初始化一个辅助对象)。复制是根据操作数的(词法)类型完成的(不是通过动态获取类)。

例如:

try {
    std::runtime_error myException("Some test message");
    std::exception &upcastedMyException = myException;
    throw upcastedMyException; //std::exception is thrown
} catch(const std::exception &caught) {
    std::cout << caught.what() << std::endl; //will output "std::exception"
}

它与其他语言不同,例如Java:

try {
    RuntimeException myException = new RuntimeException();
    Exception upcastedMyException = myException;
    throw upcastedMyException; //RuntimeException is thrown
} catch(Exception caught) {
    System.out.println(caught.getClass()); //will output "java.lang.RuntimeException"
}

因此,传递给C ++ throw的表达式具有正确的类型非常重要。在我的第一个示例中,将throw upcastedMyException替换为throw static_cast<const std::runtime_error &>(upcastedMyException)(例如)将更改输出。

关于std::make_exception_ptr

另一方面,

std::make_exception_ptr是通过throw以非常简单的方式实现的:

template<class E> std::exception_ptr make_exception_ptr(E e) noexcept {
    try {
        throw e; //note this line
    } catch(...) {
        return std::current_exception();
    }
}

这意味着std::make_exception_ptr对传递的模板参数敏感;如果未显式传递模板参数,则std::make_exception_ptr对所传递的函数参数的(词法)类型敏感(这会影响模板参数的推导):

  • 如果您在代码中执行std::make_exception_ptr(ex)(其中ex被声明为const std::exception &),则std::exception将被抛出到std::make_exception_ptr和{{1 }}将返回与std::make_exception_ptr相关的std::exception_ptr
  • 如果您在代码中执行std::exception,则std::make_exception_ptr(static_cast<const std::logic_error &>(ex))将被抛出到std::logic_error中,而std::make_exception_ptr将返回与std::make_exception_ptr相关的std::exception_ptr
  • 如果您在代码中执行std::logic_error,则std::make_exception_ptr(static_cast<const std::out_of_range &>(ex))将被抛出到std::out_of_range中,而std::make_exception_ptr将返回与std::make_exception_ptr相关的std::exception_ptr
相关问题