簡體   English   中英

捕獲后如何從 std::exception 取回原始異常?

[英]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 ethrow在此示例中的不同之處的更多詳細信息,請參見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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM