C++ 如何在std::exception\u ptr上调用what()
这是我的密码C++ 如何在std::exception\u ptr上调用what(),c++,exception,c++11,C++,Exception,C++11,这是我的密码 try { // code throws potentially unknown exception } catch (...) { std::exception_ptr eptr = std::current_exception(); // then what ? } 理想情况下,如果异常是std::exception,我希望获取与该异常相关联的字符串。try try { std::rethrow_exception(eptr); } catch
try
{
// code throws potentially unknown exception
}
catch (...)
{
std::exception_ptr eptr = std::current_exception();
// then what ?
}
理想情况下,如果异常是std::exception,我希望获取与该异常相关联的字符串。try
try
{
std::rethrow_exception(eptr);
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
{
std::返回异常(eptr);
}
捕获(const std::exception&e)
{
在我看来,std::cerr不是最好的解决方案,但似乎有效
try
{
// code throws potentially unknown exception
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
catch (...)
{
std::exception_ptr eptr = std::current_exception();
// then what ?
LogUnknownException();
}
试试看
{
//代码引发潜在的未知异常
}
捕获(const std::exception&e)
{
std::cerr在您的情况下,使用std::current_exception
似乎有点过头了,因为您似乎不想存储或复制std::exception_ptr
以供以后处理(这是它的唯一目的,它对以任何方式获取有关未知异常的附加信息都没有帮助)。如果您只想处理std::exception
的情况,那么简单的:
try
{
// code throws potentially unknown exception
}
catch (const std::exception &e)
{
std::cerr << e.what() << '\n'; // or whatever
}
catch (...)
{
// well ok, still unknown what to do now,
// but a std::exception_ptr doesn't help the situation either.
std::cerr << "unknown exception\n";
}
试试看
{
//代码引发潜在的未知异常
}
捕获(const std::exception&e)
{
标准:cerr
//然后呢
以下是:
#include <exception>
#include <stdexcept>
#include <iostream>
#include <string>
std::string what(const std::exception_ptr &eptr = std::current_exception())
{
if (!eptr) { throw std::bad_exception(); }
try { std::rethrow_exception(eptr); }
catch (const std::exception &e) { return e.what() ; }
catch (const std::string &e) { return e ; }
catch (const char *e) { return e ; }
catch (...) { return "who knows"; }
}
int main()
{
try { throw std::runtime_error("it's success!"); }
catch (...) { std::cerr << "Here is WHAT happened: " << what() << std::endl; }
try { throw 42; } catch (...) { std::cerr << "and now what: " << what() << std::endl; }
}
std::string what(const std::exception_ptr &eptr = std::current_exception());
template <typename T>
std::string nested_what(const T &e)
{
try { std::rethrow_if_nested(e); }
catch (...) { return " (" + what(std::current_exception()) + ")"; }
return {};
}
std::string what(const std::exception_ptr &eptr)
{
if (!eptr) { throw std::bad_exception(); }
try { std::rethrow_exception(eptr); }
catch (const std::exception &e) { return e.what() + nested_what(e); }
catch (const std::string &e) { return e ; }
catch (const char *e) { return e ; }
catch (...) { return "who knows"; }
}
因此,这允许在catch-all子句中获取what
但如果异常是嵌套的呢???下面是:
#include <exception>
#include <stdexcept>
#include <iostream>
#include <string>
std::string what(const std::exception_ptr &eptr = std::current_exception())
{
if (!eptr) { throw std::bad_exception(); }
try { std::rethrow_exception(eptr); }
catch (const std::exception &e) { return e.what() ; }
catch (const std::string &e) { return e ; }
catch (const char *e) { return e ; }
catch (...) { return "who knows"; }
}
int main()
{
try { throw std::runtime_error("it's success!"); }
catch (...) { std::cerr << "Here is WHAT happened: " << what() << std::endl; }
try { throw 42; } catch (...) { std::cerr << "and now what: " << what() << std::endl; }
}
std::string what(const std::exception_ptr &eptr = std::current_exception());
template <typename T>
std::string nested_what(const T &e)
{
try { std::rethrow_if_nested(e); }
catch (...) { return " (" + what(std::current_exception()) + ")"; }
return {};
}
std::string what(const std::exception_ptr &eptr)
{
if (!eptr) { throw std::bad_exception(); }
try { std::rethrow_exception(eptr); }
catch (const std::exception &e) { return e.what() + nested_what(e); }
catch (const std::string &e) { return e ; }
catch (const char *e) { return e ; }
catch (...) { return "who knows"; }
}
但是如果递归太深怎么办?如果堆栈溢出怎么办?优化了什么:
#include <typeinfo>
template <typename T>
std::exception_ptr get_nested(const T &e)
{
try
{
auto &nested = dynamic_cast<const std::nested_exception&>(e);
return nested.nested_ptr();
}
catch (const std::bad_cast &)
{ return nullptr; }
}
#if 0 // alternative get_nested
std::exception_ptr get_nested()
{
try { throw ; }
catch (const std::nested_exception &e) { return e.nested_ptr(); }
catch (...) { return nullptr ; }
}
#endif
std::string what(std::exception_ptr eptr = std::current_exception())
{
if (!eptr) { throw std::bad_exception(); }
std::string whaaat;
std::size_t num_nested = 0;
next:
{
try
{
std::exception_ptr yeptr;
std::swap(eptr, yeptr);
std::rethrow_exception(yeptr);
}
catch (const std::exception &e) { whaaat += e.what() ; eptr = get_nested(e); }
catch (const std::string &e) { whaaat += e ; }
catch (const char *e) { whaaat += e ; }
catch (...) { whaaat += "who knows"; }
if (eptr) { whaaat += " ("; num_nested++; goto next; }
}
whaaat += std::string(num_nested, ')');
return whaaat;
}
UPD
类似的功能可以在C++03中实现,方法是使用允许在catch块之外重新抛出当前异常的技巧:对于异常不是从std::exception
派生的情况,您可能也应该做些什么……在OP的情况下,由于OP已经是i,所以它是高度冗余的n一个catch
块。一般来说,我认为这不起作用,因为它可能会干扰已经抛出的异常。@KerrekSB是的,可能我们应该捕获任何异常并打印一些关于“未知错误”的内容…KonradRudolph无论如何,标准上没有其他情况。我们可以编写函数并在一个try/catch块后调用它。最终它似乎根本不需要std::exception\u ptr
。那么std::exception\u ptr的真正用途是什么?@Ram它的用途是存储和复制一个异常(可能有任意类型)。它是一种拥有智能指针。想象一下它就像一个std::shared_ptr
,只不过它适用于任何类型的任何异常(这就是它也不提供任何类型信息的原因)。这对于在线程之间传播异常特别有用,例如,std::promise
需要存储发生的异常,以便稍后在另一个线程中尝试访问std::future
的值时重试。@Ram最后,每当您想存储抛出的异常以供以后使用时,它都很有用(通常情况下,它会在捕获块结束后被销毁)。请参阅及其相关页面。“在您的情况下似乎有点过头了…”这并没有改变它可能是一个MCVE,或者为了拥有一个代码段而成为一个代码段。这并没有回答这个问题,这对我们这些正在寻找它的人来说真的很沮丧。这将打印(至少)异常类型:std::cout name():“null”)在这里使用current\u exception
是毫无意义的,它不会添加任何内容。与其使用dynamic\u cast
-catch bad\u cast
-return nullptr
,不如使用dynamic\u cast
指针,而不是引用。您的意思是在第二个代码块中使用nested\u what
上一个代码示例有一个嵌套的num_
计数器,您可以对其进行递增,但从未对其进行过测试。这可能是无用的,或者您想以某个数字打破循环?另外,使用(;;)的可以很容易地删除您的goto
循环和中断
当eptr==nullptr
时。我们为什么需要重新显示它?有一个建议为std::exception\u ptr添加类型内省:
#include <typeinfo>
template <typename T>
std::exception_ptr get_nested(const T &e)
{
try
{
auto &nested = dynamic_cast<const std::nested_exception&>(e);
return nested.nested_ptr();
}
catch (const std::bad_cast &)
{ return nullptr; }
}
#if 0 // alternative get_nested
std::exception_ptr get_nested()
{
try { throw ; }
catch (const std::nested_exception &e) { return e.nested_ptr(); }
catch (...) { return nullptr ; }
}
#endif
std::string what(std::exception_ptr eptr = std::current_exception())
{
if (!eptr) { throw std::bad_exception(); }
std::string whaaat;
std::size_t num_nested = 0;
next:
{
try
{
std::exception_ptr yeptr;
std::swap(eptr, yeptr);
std::rethrow_exception(yeptr);
}
catch (const std::exception &e) { whaaat += e.what() ; eptr = get_nested(e); }
catch (const std::string &e) { whaaat += e ; }
catch (const char *e) { whaaat += e ; }
catch (...) { whaaat += "who knows"; }
if (eptr) { whaaat += " ("; num_nested++; goto next; }
}
whaaat += std::string(num_nested, ')');
return whaaat;
}
Here is WHAT happened: "success!"
here is what: "run() failed (Couldn't open nonexistent.file (basic_ios::clear))"