C++调用Python(Boost.Python):如何判断抛出对象类型?
在C++的catch(...)分支中判断抛出对象的类型
通用方法:利用std::current_exception()重新捕获
在catch(...)分支里,你可以重新抛出异常并尝试针对性捕获,以此识别类型,但这种方式对非多态类型(无虚函数的类)效果有限:
catch(...) { try { std::rethrow_exception(std::current_exception()); } catch(const std::exception& e) { std::cout << "异常类型:" << typeid(e).name() << ",信息:" << e.what() << std::endl; } catch(const std::string& s) { std::cout << "抛出字符串:" << s << std::endl; } catch(const char* s) { std::cout << "抛出C字符串:" << s << std::endl; } catch(...) { // 走到这里说明是非多态类型或特殊类型,尝试编译器特定方法 } }
针对Boost.Python场景的特殊处理
你是从C++调用Python,大概率抛出的是Boost.Python包装的Python异常,这类异常不会被标准catch分支捕获,直接用Boost.Python的工具处理即可:
#include <boost/python/exception.hpp> #include <boost/python/handle.hpp> #include <boost/python/str.hpp> #include <boost/python/extract.hpp> try { instruction(); } catch(my_own_namespace::Exception const& e) { /* 处理自定义异常 */ } catch(std::exception const& e) { /* 处理标准异常 */ } catch(const boost::python::error_already_set&) { // 获取并解析Python异常 PyObject* exc_type = PyErr_Occurred(); if(exc_type) { // 获取异常类型名称 boost::python::handle<> handle_type(exc_type); boost::python::str type_str(handle_type); std::cout << "Python异常类型:" << boost::python::extract<std::string>(type_str)() << std::endl; // 获取异常详情 PyObject* exc_value = PyErr_GetArg(); if(exc_value) { boost::python::handle<> handle_value(exc_value); boost::python::str value_str(handle_value); std::cout << "Python异常信息:" << boost::python::extract<std::string>(value_str)() << std::endl; } PyErr_Clear(); // 清除Python异常状态 } } catch(std::string const& s) { /* 处理字符串异常 */ } catch(char const* s) { /* 处理C字符串异常 */ } catch(...) { // 兜底处理,用编译器特定方法获取类型 const std::type_info* ti = __cxa_current_exception_type(); if(ti) { std::cout << "混淆后的异常类型名:" << ti->name() << std::endl; // 可以用c++filt -t 命令解析混淆后的名称,得到可读类型 } }
编译器特定的类型识别
GCC/Clang支持__cxa_current_exception_type()函数,能直接获取异常的std::type_info指针,哪怕是非多态类型也能得到类型名(只是名称经过编译器混淆,需要用c++filt工具解析):
#include <typeinfo> catch(...) { const std::type_info* ti = __cxa_current_exception_type(); if(ti) { std::cout << "混淆后的类型名:" << ti->name() << std::endl; // 示例:输出如果是NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE,用c++filt解析后是std::__cxx11::basic_string<char> } }
内容的提问来源于stack exchange,提问作者Caduchon
相关产品推荐
相关产品推荐

