我可以让 std::optional<std::exception>::value() 返回(多态)继承的异常,而不是 std::exception 吗?

Can I make std::optional<std::exception>::value() return the (polymorphic) inherited exception, and not std::exception?

提问人:Wololo 提问时间:6/15/2023 最后编辑:Wololo 更新时间:6/15/2023 访问量:70

问:

显然,投掷和接球不能多态处理。首先,如果我们考虑std::optional<std::exception>::value()

try
{
    throw std::logic_error("blah ..");
}
catch(const std::exception& e)
{
    std::cout << "E: " << e.what() << std::endl; // OK, outputs "blah .."
}

我们得到了预期的输出,但如果我们尝试

std::optional<std::exception> error = std::logic_error("Booo ..");
try
{
    throw error.value();
}
catch(const std::exception& e)
{
    std::cout << "E: " << e.what() << std::endl; // NOPE, outputs "std::exception"
}

异常对象被切片。

我知道这是因为我实际上抛出了可选的模板类型,即 and not .也就是说,我们基本上将第一个示例中的表达式更改为std::exceptionstd::logic_errorthrow

std::exception err = std::logic_error("Blah ..");
throw err;

这给出了相同的行为。

那么,我怎样才能使我的退货成为派生异常呢?它必须包含指针吗?std::optional<std::exception>::value()

C++ 异常 C++17 std可选

评论

0赞 fabian 6/16/2023
这不能用 来完成,因为 C++ 标准要求不使用任何动态分配,即对象存储为对象本身的成员,而不是使用指向对象的指针。由于这个原因,你永远无法阻止对象切片:没有足够的内存让对象存储包裹在...std::optionalstd::optionalstd::optionalstd::optional

答:

4赞 StoryTeller - Unslander Monica 6/15/2023 #1

如果要在可能包含也可能不包含异常的值类型中传递异常,以及异常类型的类型擦除,则您从标准库中使用了错误的工具。这就是 std::exception_ptr 的用途:它的存在是为了传递抛出(或准备抛出)异常句柄。

auto error = std::make_exception_ptr(std::logic_error("blah .."));
// stuff 
try {
  std::rethrow_exception(std::move(error));
} catch (std::exception const& e) {
    std::cout << "E: " << e.what() << std::endl; 
}

在这里,它是在 godbolt 上直播的。

std::exception_ptr是标准库如何弥合需要在执行点周围移动异常的库代码与核心异常机制之间的差距。因此,它不仅限于派生自 的异常,因为我们可以在 C++ 中抛出任意类型。std::exception