stl 中的错误代码是否有任何异常?

man*_*ans 1 c++ boost stl exception

我阅读了一些关于异常和错误代码的使用以及它们何时适合的讨论。

我相信在我的情况下例外更好,但我有一个具体问题:

如果我抛出一个 std::runtime_error("this is an error") 然后我抓住了它,我找不到错误是什么,我只知道有一个错误。

我正在寻找的是一个异常,我可以抛出并为其添加错误代码,以便稍后我可以在捕获它时检查错误代码,例如:

 enum errorCodes
 {
        error_1,
        error_2,
        error_3
 }

 try
 {
     throw std::runtime_error(error_1,"can not do the job!");
 }
 catch (std::runtime_error & err)
 {
     switch (err.errorCode)
     {
         case error_1:
            // I can not contunue, so re throw it
             rethrow err;
         case error_2:
            // it is not important for me, so I can continue
           break;
        case error_3: 
            //Oh, I need to do something before continue
            re_init();
            break;
        default:
             rethrow err;
  }
Run Code Online (Sandbox Code Playgroud)

我可以写这样的异常,但在这样做之前,我想知道 STL 或 BOOST 中是否存在这种类型的异常?

有没有更好的方法来做到这一点(我对抛出不同类型的异常不感兴趣,因此从我的角度来看,捕获不同类型的异常不是解决方案。

Che*_*Alf 5

是的,有std::system_error。它来源于std::runtime_error. 它非常面向 Unix 领域,但它确实支持一般的错误代码,我建议您以这种方式使用它。


以下代码演示了如何为特定于应用程序的错误代码定义自己的错误类别:

#include <string>
#include <system_error>
#include <typeinfo>

namespace my{
    struct Error_code
    {
        enum Enum
        {
            error_1 = 101,
            error_2 = 102,
            error_3 = 103
        };
    };

    class App_error_category
        : public std::error_category
    {
    using Base = std::error_category;
    public:
        auto name() const noexcept
            -> char const*
            override
        { return "App error"; }

        auto default_error_condition( int const code ) const noexcept
            -> std::error_condition
            override
        { (void) code; return {}; }

        auto equivalent( int const code, std::error_condition const& condition ) const noexcept
            -> bool
            override
        { (void) code; (void) condition; return false; }

        // The intended functionality of this func is pretty unclear.
        // It apparently can't do its job (properly) in the general case.
        auto equivalent( std::error_code const& code, int const condition ) const noexcept
            -> bool
            override
        { return Base::equivalent( code, condition ); }

        auto message( int const condition ) const
            -> std::string
            override
        { return "An application error occurred, code = " + std::to_string( condition ); }

        constexpr
        App_error_category(): Base{} {}
    };

    auto app_error_category()
        -> App_error_category const&
    {
        static App_error_category the_instance;
        return the_instance;
    }

    class App_error
        : public std::system_error
    {
    using Base = std::system_error;
    public:
        auto app_error_code() const
            -> Error_code::Enum
        { return static_cast<Error_code::Enum>( code().value() ); }

        App_error( Error_code::Enum const code )
            : Base{ code, app_error_category() }
        {}

        App_error( Error_code::Enum const code, std::string const& description )
            : Base{ code, app_error_category(), description }
        {}
    };

}  // namespace my

void foo()
{
    try
    {
        throw my::App_error( my::Error_code::error_1, "can not do the job!" );
    }
    catch( my::App_error const& x )
    {
        switch( x.app_error_code() )
        {
        case my::Error_code::error_1:
            // I can not contunue, so re throw it
            throw;
        case my::Error_code::error_2:
            // it is not important for me, so I can continue
            break;
        case my::Error_code::error_3: 
            //Oh, I need to do something before continue
            //re_init();
            break;
        }
    }
}

#include <iostream>
#include <stdlib.h>     // EXIT_SUCCESS, EXIT_FAILURE
using namespace std;
auto main()
    -> int
{
    try
    {
        foo();
        return EXIT_SUCCESS;
    }
    catch( exception const& x )
    {
        cerr << "!" << x.what() << endl;
    }
    return EXIT_FAILURE;
}
Run Code Online (Sandbox Code Playgroud)

使用 Visual C++ 2015 和 MingW g++ 6.4.0 这会产生输出

!cannot do the job!: 发生应用程序错误,代码 = 101

一般来说,定义特定的异常类比使用错误代码更实用。但是,对于系统错误代码,将这些代码与异常一起传递更为实用。为此可以避免上面显示的复杂性,因为std::system_category非常适合。

简而言之,这里的复杂性源于您要求不随波逐流,而是要逆流而上。