是否可以在不同的类中编写/包装异常处理组件(try、catch)
Is it possible to write/wrap the exception handling components (try,catch) in different class?
这是关于将异常处理逻辑封装在某种类中。写c时++代码,很多时候我们需要捕获许多类型/变体的异常,这取决于客户端抛出的异常。这导致我们在catch()子句中(多次)编写类似类型的代码。
在下面的示例中,我编写了函数(),它可以以多种可能的形式抛出异常
我想知道是否有可能以类的形式编写/包装这样的逻辑,这样最终用户就必须同时编写类似类型的代码这有意义吗
#include<vector>
#include<string>
#include<exception>
#include<iostream>
// this function can throw std::exception, std::string, int or unhandled
void function() {
std::vector<int> x{1,2,3,4,5};
auto val = x.at(x.size()); //throw out-of-range error
}
int main() {
try { function(); }
catch(std::exception& e) { std::cout<<e.what()<<std::endl; }
catch(std::string& msg) { std::cout<<msg<<std::endl; }
catch(int i) { std::cout<<i<<std::endl; }
catch(...) { std::cout<<"Unhandled Exception"<<std::endl; }
return 0;
}
到目前为止,我以这种方式和下面的方式认为是伪逻辑。
class exceptionwrapper{ exceptionwrapper(function pointer* fp) { // functions which would be executing inside try } ~exceptionwrapper() { // all catch() clause can be written over here // or some other member function of this class } };
这个类的对象可以通过这种方式在main()中实例化。
int main() {
exceptionwrapper obj(function);
//here execptionwrapper destructor would take care about calling all type of catch
}
使用std::exception_ptr
:是可能的
实时演示链接。
#include <iostream>
#include <exception>
#include <stdexcept>
void universal_exception_handler(std::exception_ptr e)
{
try
{
std::rethrow_exception(e);
}
catch (const std::logic_error& e)
{
std::cout << "logic_error" << std::endl;
}
catch (const std::runtime_error& e)
{
std::cout << "runtime_error" << std::endl;
}
}
void foo()
{
throw std::logic_error{""};
}
void bar()
{
throw std::runtime_error{""};
}
int main()
{
try
{
foo();
}
catch (...)
{
universal_exception_handler(std::current_exception());
}
try
{
bar();
}
catch (...)
{
universal_exception_handler(std::current_exception());
}
}
您也可以在没有std::exception_ptr
的情况下实现这一点,只需将throw;
放在std::rethrow_exception(e);
的位置,希望只有当有一个活动异常正在处理时,该函数才会被调用(否则您的程序将被terminate()'
ed):
void universal_exception_handler()
{
try
{
throw;
}
catch (const std::logic_error& e)
{
std::cout << "logic_error" << std::endl;
}
catch (const std::runtime_error& e)
{
std::cout << "runtime_error" << std::endl;
}
}
try
{
foo();
}
catch (...)
{
universal_exception_handler();
}
还有另一个现场演示链接。
你想要的是可能的,但我认为这不是很有用。首先,让我们实现一种机制来接受一个可调用对象及其相关参数,我们将在exception_wrapper
的析构函数中调用这些参数。
template<typename Func, typename... Args>
struct exception_wrapper
{
exception_wrapper(Func f, Args... args)
: f_(std::move(f))
, args_(std::make_tuple(std::move(args)...))
{}
~exception_wrapper()
{
try {
invoke();
} catch(std::exception const& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
} catch(...) {
std::cerr << "Caught unknown exception" << std::endl;
}
}
template<std::size_t... I>
void apply(std::index_sequence<I...>)
{
f_(std::get<I>(args_)...);
}
void invoke()
{
apply(std::index_sequence_for<Args...>());
}
Func f_;
std::tuple<Args...> args_;
};
template<typename Func, typename... Args>
auto make_exception_wrapper(Func&& f, Args&&... args)
{
return exception_wrapper<Func, Args...>(
std::forward<Func>(f), std::forward<Args>(args)...);
}
这就利用了C++14std::integer_sequence
;如果这在您的实现中不可用,那么SO上有几个答案可以展示如何自己实现它(例如这个)。
要使用它,请创建一个exception_wrapper
对象,当析构函数执行时,您的函数将被调用。
make_exception_wrapper(function);
现场演示
现在,我认为这没有用,因为通常情况下,只有当代码能够处理异常并继续正常操作时,才应该捕获异常。否则,让它们传播到您可能想要安装处理程序的顶层,这样您就可以优雅地退出程序。
考虑到这一点,不太可能有一种通用的方法来处理代码引发的所有异常,这会大大降低exception_wrapper
的实用性。您可以将其修改为采用另一个可调用的参数,即异常处理程序,该异常处理程序将传递给捕获的std::exception
对象,这使该类更加通用。
此外,调用析构函数中的函数意味着不能将返回值(如果有的话)传递回调用者。这可以通过调用exception_wrapper::operator()
中的函数来解决,但这会增加在确实抛出异常的情况下返回的内容,并且您已经抑制了它
最后,不要编写抛出不是从std::exception
派生的类型的代码。这使您的代码变得单一,如果您确实想处理异常,则需要像您的示例中那样,在代码中添加几个catch
语句。
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- 当我使用 C++ 中的 C# dll 来使用 Selenium 时,存在异常处理问题
- Firebase C++VS2018 SDL2-在Firebase::app::create(..)上执行异常处理
- 使用 stoi 功能进行异常处理
- 子系统中的异常处理:本机
- 与异常处理程序中的操作员<<不匹配
- 数组 C++ 上的异常处理程序
- 异常处理:如果用户输入不是三个特定字符之一
- C++ 异常处理错误输出
- 视觉 std::矢量无异常:警告 C4530:使用了C++异常处理程序,但未启用展开语义.指定 /EHsc
- C++交换机状态异常处理
- 在字符串类上的成员函数和out_of_range异常处理
- 奇怪的消息 (_Base_bitset::_M_do_to_ulong) 从溢出异常处理程序中打印出来
- 执行视觉工作室异常处理模式
- 为什么隐式转换在异常处理中从派生到基?
- C++执行期间的类成员函数错误/异常处理
- C++ 中未处理的异常处理程序
- 用户定义的异常处理
- C :ScopeGuard vs返回支票和异常处理
- 是否可以在不同的类中编写/包装异常处理组件(try、catch)