使用 std::make_exception_ptr 的奇怪行为

ypn*_*nos 0 c++ exception c++11

我想知道为什么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);
Run Code Online (Sandbox Code Playgroud)

而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;
    }
}
Run Code Online (Sandbox Code Playgroud)

输出如下:

(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
Run Code Online (Sandbox Code Playgroud)

但是我希望得到以下输出:

(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)
Run Code Online (Sandbox Code Playgroud)

我在这里缺少什么?

Sas*_*sha 6

关于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"
}
Run Code Online (Sandbox Code Playgroud)

它与其他语言不同,例如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"
}
Run Code Online (Sandbox Code Playgroud)

因此,传递给 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 如果您std::make_exception_ptr(ex)在代码中执行此操作(其中ex声明为const std::exception &),则将std::exception被抛出std::make_exception_ptrstd::make_exception_ptr返回std::exception_ptr与 相关的内容std::exception
  • 如果您std::make_exception_ptr(static_cast<const std::logic_error &>(ex))在代码中这样做,则 thenstd::logic_error将被抛出std::make_exception_ptrstd::make_exception_ptr返回std::exception_ptr与 相关的内容std::logic_error
  • 如果您std::make_exception_ptr(static_cast<const std::out_of_range &>(ex))在代码中这样做,则 thenstd::out_of_range将被抛出std::make_exception_ptrstd::make_exception_ptr返回std::exception_ptr与 相关的内容std::out_of_range


Ric*_*ges 5

std::make_exception_ptr()按值获取其参数。这意味着复制或就地构建。

您正在制作 std::exception 的副本(即切片)

  • 我知道它是 http://en.cppreference.com/w/cpp/error/make_exception_ptr 中所述的副本。但这为什么重要呢? (2认同)