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

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

问题描述

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



在下面的示例中,我写了一个函数(),它可以以许多可能的形式抛出异常。



我想知道是否可以以类的形式编写/包装这样的逻辑,以便最终用户必须立即编写类似类型的代码。 它是否有意义或有任何意义?

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

//此函数可以抛出std :: exception,std :: string,int或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){
//函数将在里面执行try
}
〜exceptionwrapper(){
//所有catch()子句可以写在这里
//或一些其他成员函数of this class
}

};


此类的对象可以在

$ main()

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


解决方案

你要求的是可能的,但我不认为这是非常有用的。首先让我们实现一个接受一个可调用对象及其关联的参数的机制,我们将在 exception_wrapper 的析构函数中调用。

 模板< 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)
{
return exception_wrapper< Func,Args ...>(
std :: forward(Func)(f),std :: forward< Args(args)...);
}

这使用C ++ 14 std :: integer_sequence ;如果您的实现上没有这些选项,您可以通过几个答案解释如何自己实现(例如这一个) 。



要使用它,创建一个 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天全站免登陆