[英]How to get original exception back from std::exception once caught?
// Example program
#include <iostream>
#include <string>
#include <stdexcept>
void log(const std::exception& e) {
try {
throw e;
}
catch (const std::logic_error& e1) {
std::cout << "logic_error: " << e1.what() << std::endl; // How to get logic_error back once caught?
}
catch (const std::exception& e1) {
std::cout << "exception: " << e1.what() << std::endl;
}
}
int main()
{
try {
throw std::logic_error("sth wrong");
}
catch (const std::exception& e) {
log(e);
}
}
我不想添加更多的 catch 子句是因為我想有一個中心位置來記錄詳細的異常消息,不同的異常可能會有很大的不同。
有沒有辦法將 std::exception 縮小到 catch 子句中的派生異常?
您可以在log
方法中重新拋出原始異常以保留其原始 state。 這樣,一切都應該按照您的預期工作。
修改后的log
方法如下所示:
void log(const std::exception& e) {
try {
throw;
}
catch (const std::logic_error& e1) {
std::cout << "logic_error: " << e1.what() << std::endl;
}
catch (const std::exception& e1) {
std::cout << "exception: " << e1.what() << std::endl;
}
}
有關throw e
和throw
在此示例中的不同之處的更多詳細信息,請參見throw 表達式。
std::exception::what()
是virtual
的。 所以你不需要取回原始類型來寫日志。 您只需確保為繼承std::exception
的自定義異常重新定義what()
。
這可能變成:
void log(const std::exception & e)
{
std::cout << e.what() << std::endl;
}
您可以使用std::rethrow_exception
:
void log(std::exception_ptr eptr) {
try {
if (eptr) {
std::rethrow_exception(eptr);
}
}
catch (const std::logic_error& e1) {
std::cout << "logic_error: " << e1.what() << std::endl;
}
catch (const std::exception& e1) {
std::cout << "exception: " << e1.what() << std::endl;
}
}
int main()
{
try {
throw std::logic_error("sth wrong");
}
catch (const std::exception&) { // or even catch (...)
log(std::current_exception());
}
}
您不必只使用標准庫提供的基本異常,您可以使用所需的方法創建自己的異常層次結構。
#include <exception>
#include <string>
#include <iostream>
class MyBaseException: public std::exception
{
public:
virtual std::string output() const = 0;
/* Define methods you need here */
};
class MySpecificException : public MyBaseException
{
public:
const char* what() const noexcept override {return "error"; }
std::string output() const override { return "Specific debug output that I want"; }
};
int main(){
try{
throw MySpecificException{};
}catch(const MyBaseException& e){
std::cout << e.output() << '\n';
}catch(const std::exception& e) {
std::cout << e.what() << '\n';
}
}
您可以使用運行時類型信息來獲取執行的類型:
#include <iostream>
#include <string>
#include <stdexcept>
#include <typeinfo>
#if defined(__clang__) || defined(__GNUC__)
#include <cxxabi.h>
#endif
std::string getTypename(const std::exception& e)
{
#if defined(__clang__) || defined(__GNUC__)
// .name() returns a mangled name on gcc and clang
int status;
return abi::__cxa_demangle(typeid( e ).name(), 0, 0, &status);
#else
// visual studio returns a human readable name
return typeid( e ).name();
#endif
}
void log(const std::exception& e) {
std::cout << getTypename( e ) << ": " << e.what() << std::endl;
}
int main()
{
try {
throw std::logic_error("sth wrong");
}
catch (const std::exception& e) {
log(e);
}
}
getTypename()
方法可能不適用於所有平台,您可能需要根據需要對其進行調整。 您可能想要使用boost::core::demangle而不是直接調用 gcc demangle API。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.