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

huangapple go评论73阅读模式
英文:

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&lt;std::exception&gt;::value() cannot be handled polymorphically. First if we consider

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

We get get the expect output, but if we try

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

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(&quot;Blah ..&quot;);
throw err;

which gives the same behavior.

So how can I make my std::optional&lt;std::exception&gt;::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(&quot;blah ..&quot;));
// stuff 
try {
  std::rethrow_exception(std::move(error));
} catch (std::exception const&amp; e) {
    std::cout &lt;&lt; &quot;E: &quot; &lt;&lt; e.what() &lt;&lt; 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++.

huangapple
  • 本文由 发表于 2023年6月15日 16:47:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76480712.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定