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

查看:167
本文介绍了是否可能在不同的类中编写/包装异常处理组件(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<未处理的异常<< std :: endl; }
return 0;
}

到目前为止,我以为这样和以下是伪逻辑即可。


  class exceptionwrapper {
exceptionwrapper(function pointer * fp){
//函数将执行内部尝试
}
〜exceptionwrapper(){
//所有的catch()子句可以写在这里
//或其他一些成员函数的这个班
}

};


此类的对象可以在 main()以这种方式。

  int main(){
exceptionwrapper obj(function);
//这里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_;
};

模板< typename Func,typename ... Args>
auto make_exception_wrapper(func&& f,Args&&args)args
{
return 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派生的类型: :例外。这使您的代码成为单一的,如果您想要处理异常,则需要使用多个 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天全站免登陆