Man*_*mar 6 c++ exception-handling raii c++11
这是关于在某种类中包装异常处理逻辑.在编写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;
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,我以这种方式思考,下面是伪逻辑.
Run Code Online (Sandbox Code Playgroud)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
}
Run Code Online (Sandbox Code Playgroud)
Pio*_*cki 13
有可能使用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());
}
}
Run Code Online (Sandbox Code Playgroud)
你也可以做到这一点没有std::exception_ptr,只是把throw;到位的std::rethrow_exception(e);,希望这个函数被调用只要有正在处理活动异常(否则你的程序将被terminate()'编):
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();
}
Run Code Online (Sandbox Code Playgroud)
你所要求的是可能的,但我认为这不是很有用。首先,让我们实现一个接受可调用对象及其关联参数的机制,我们将在 的析构函数中调用它们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)...);
}
Run Code Online (Sandbox Code Playgroud)
这利用了 C++14 std::integer_sequence;如果这在您的实现中不可用,那么有几个答案可以展示如何自己实现它(例如这个)。
要使用它,请创建一个exception_wrapper对象,当析构函数执行时将调用您的函数。
make_exception_wrapper(function);
Run Code Online (Sandbox Code Playgroud)
现在,我认为这没有用,因为一般来说,您应该只在代码能够处理异常的情况下捕获异常,并继续正常运行。否则,让它们传播到您可能想要安装处理程序的顶层,以便您可以优雅地退出程序。
鉴于此,不太可能有一种通用方法来处理代码抛出的所有异常,这大大降低了exception_wrapper实现的实用性。您可以修改它以采用另一个可调用参数,即异常处理程序,该异常处理程序将传递std::exception捕获的对象,这使得该类更加通用。
此外,在析构函数中调用该函数意味着您无法将返回值(如果有)传递回调用者。这可以通过调用其中的函数来解决exception_wrapper::operator(),但这会增加在确实抛出异常的情况下返回的内容的问题,并且您已经抑制了它。
最后,不要编写抛出非派生类型的代码std::exception。这使得您的代码变得不惯用,如果您确实想处理异常,则需要在代码中添加多个catch语句,就像您在示例中所做的那样。
| 归档时间: |
|
| 查看次数: |
1934 次 |
| 最近记录: |