是否可以在不同的类中编写/包装异常处理组件(try,catch)? [英] Is it possible to write/wrap the exception handling components (try,catch) in different class?

查看:121
本文介绍了是否可以在不同的类中编写/包装异常处理组件(try,catch)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是关于将异常处理逻辑包装在某种类中。在编写c ++
代码时,很多时候我们需要根据客户端抛出的异常捕获许多类型/异常类型。这导致我们在catch()子句中多次编写类似类型的代码。



在下面的示例示例中,我编写了function(),该函数可以多种可能的形式引发异常。



我想知道是否有可能以类的形式编写/包装这种逻辑,以便最终用户不得不一次编写类似类型的代码? 这有意义还是有意义?

 #include< vector> 
#include< string>
#include< exception>
#include< iostream>

//此函数可以抛出std :: exception,std :: string,int或未处理的
void function(){
std :: vector< int> x {1,2,3,4,5};
自动val = x.at(x.size()); //抛出超出范围的错误
}

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<<未处理的异常<< std :: endl; }
返回0;
}

到目前为止,我一直以这种方式认为以下是伪逻辑


 类exceptionwrapper {
exceptionwrapper(函数指针* fp){
//将在try
内部执行的函数}
〜exceptionwrapper(){
//所有catch()子句都可以写在这里
//或其他一些成员函数此类
}

};


此类的对象可以在中实例化

  int main(){
exceptionwrapper obj(function);
//这里execptionwrapper析构函数将注意调用所有类型的catch
}


解决方案

您所要求的是可能的,但我认为这不是很有用。首先,我们实现一种机制来接受可调用对象及其相关参数,我们将在 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<< 捕获的例外:<< e.what()<< std :: endl;
} catch(...){
std :: cerr<< 捕获的未知异常<< 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)
{
返回exception_wrapper< Func,Args ...>(
std :: forward(func)(f),std :: forward Args(args)...);
}

这利用了C ++ 14 std :: integer_sequence ;如果在您的实现上不可用,那么在SO上有几个答案说明了如何自己实现(例如,



要使用它,请创建一个 exception_wrapper 对象,并且在执行析构函数时将调用您的函数。 / p>

  make_exception_wrapper(function); 

实时演示






现在,我认为这没有用,因为通常,只有在代码能够处理异常并继续正常运行的情况下,才应捕获异常。否则,让它们传播到您可能要安装处理程序的顶层,以便您可以正常退出程序。



鉴于此,不太可能有一种通用的方法来处理代码引发的所有异常,这大大降低了 exception_wrapper的实用性已实施。您可以对其进行修改以采用另一个可调用的参数,该异常处理程序将传递给捕获的 std :: exception 对象,这使该类更加通用。 / p>

此外,在析构函数中调用该函数意味着您无法将返回值(如果有的话)传递回调用方。可以通过调用 exception_wrapper :: operator()中的函数来解决此问题,但是如果确实抛出异常,这会增加返回值的皱纹,并且



最后,请勿编写代码,该代码将抛出不是从 std派生的类型: :exception 。这使您的代码变得与众不同,并且,如果您确实想处理该异常,则需要使用几个 catch 语句来填充代码,就像您的示例中那样。


This is about wrapping the exception handling logic in some sort of class. While writing c++ code, many time we need to catch many type/variants of exception depending on what client throw. This lead us to write similar types of code(many times) in catch() clause.

In below sample example, I have written the function(), which can throw exception in the many possible form.

I wanted to know is it possible to write/wrap such logic in the form of class so that end user would have to write similar types of code at once place?. Does it make any sense or it has any meaning?

#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;
}

So far I thought in this way and below is the pseudo logic.

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
}

};

The object of this class can be instantiated in the main() in this way.

int main() {
 exceptionwrapper obj(function);
 //here execptionwrapper destructor would take care about calling all type of catch
}

解决方案

What you're asking for is possible, but I don't think it's very useful. First let's implement a mechanism to accept a callable object, and its associated arguments, which we'll invoke in the destructor of 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)...);
}

This makes use of the C++14 std::integer_sequence; if that's not available on your implementation there are several answers on SO that show how to implement it yourself (this one for instance).

To use it, create an exception_wrapper object, and your function will be invoked when the destructor executes.

make_exception_wrapper(function);

Live demo


Now, I don't think this is useful because in general you should only catch exceptions if your code is able to handle them, and continue operating normally. Otherwise let them propagate to the top level where you might want to install a handler so it allows you to exit the program gracefully.

Given that, it's unlikely that there'll be a common approach to handling all exceptions thrown by your code, which greatly reduces the utility of exception_wrapper as implemented. You could modify it to take another callable argument, the exception handler that will be passed the std::exception object that was caught, which makes the class a little more generic.

Additionally, invoking the function in the destructor means you cannot pass the return value, if any, back to the caller. This can be fixed by invoking the function within exception_wrapper::operator() instead, but that then adds the wrinkle of what to return in the case an exception is indeed thrown, and you've suppressed it.

Finally, do not write code that throws types that are not derived from std::exception. This makes your code unidiomatic, and if you do want to handle the exception, you'll need to litter the code with several catch statements, like you have in your example.

这篇关于是否可以在不同的类中编写/包装异常处理组件(try,catch)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆