英文:
Can I make std::optional<std::exception>::value() return the (polymorphic) inherited exception, and not std::exception?
问题
显然,抛出和捕获 std::optional<std::exception>::value()
不能以多态方式处理。首先,考虑以下情况:
try
{
throw std::logic_error("blah ..");
}
catch(const std::exception& e)
{
std::cout << "E: " << e.what() << std::endl; // 正确,输出 "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; // 不行,输出 "std::exception"
}
异常对象被切片。
我理解这是因为我实际上是在抛出 optional 的模板类型,即 std::exception
,而不是 std::logic_error
。也就是说,我们基本上将第一个示例中的 throw
表达式更改为:
std::exception err = std::logic_error("Blah ..");
throw err;
这会产生相同的行为。
那么,如何能够使我的 std::optional<std::exception>::value()
返回一个派生的异常呢?它是否必须包含一个指针?
英文:
Apparently, throwing and catching std::optional<std::exception>::value()
cannot be handled polymorphically. First if we consider
try
{
throw std::logic_error("blah ..");
}
catch(const std::exception& e)
{
std::cout << "E: " << e.what() << std::endl; // OK, outputs "blah .."
}
We get get the expect output, but if we try
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"
}
The exception object got sliced.
I understand that this is because I'm actually throwing optional's template type, which is std::exception
and not std::logic_error
. That is, we basically changed the throw
expression in the first example to
std::exception err = std::logic_error("Blah ..");
throw err;
which gives the same behavior.
So how can I make my std::optional<std::exception>::value()
return a derived exception? Does it have to contain a pointer?
答案1
得分: 4
Here is the translated content:
如果您想在可能包含异常的值类型中传递异常,以及对异常类型进行类型抹消,那么您选择了标准库中错误的工具。这就是 std::exception_ptr
的用途:它存在以传递已抛出(或准备抛出)的异常句柄。
auto error = std::make_exception_ptr(std::logic_error("blah .."));
// 一些操作
try {
std::rethrow_exception(std::move(error));
} catch (std::exception const& e) {
std::cout << "E: " << e.what() << std::endl;
}
您可以在 godbolt 上查看示例。
std::exception_ptr
是标准库用来弥合需要在执行点之间传递异常的库代码与核心异常机制之间的差距的方式。因此,它不仅限于派生自 std::exception
的异常,我们还可以在 C++ 中抛出任意类型的异常。
英文:
If you want to pass exceptions around in a value type that may or may not hold them, along with type erasure of the exception type, you turned to the wrong tool from the standard library. That's what std::exception_ptr
is for: it exists to pass a thrown (or ready to to be thrown) exception handle around.
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;
}
Here it is live on godbolt.
std::exception_ptr
is how the standard library bridges the gap between library code that needs to move exceptions around points of execution, and the core exception mechanism. Due to this, it isn't limited to just exceptions derived from std::exception
, as we can throw arbitrary types in C++.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论