在c ++

时间:2019-04-09 07:47:56

标签: c++ error-handling c++17

我想创建一个类和枚举来处理项目中的错误。到目前为止,我正在按照以下方式进行操作。

enum class eErrorType
{
    eJsonFileNotFound = 0,
    eJsonInvalidFormat,
    eJsonKeyNotFound,
    eJsonEmptyArray,
    eNoError,
    eCustom
};


class Error
{
public:
    // Constructors                                                                     
    Error() { errorType = eErrorType::eNoError; message = ""; }
    Error(eErrorType type) { errorType = type; SetMessage(type); }
    Error(std::string msg) { errorType = eErrorType::eCustom; message = msg; }

    // Public Methods                                                                   
    std::string getErrMessage() { return message; }


private:

    eErrorType errorType;
    std::string message;
    void SetMessage(eErrorType type)
    {
        switch (type)
        {
        case eErrorType::eJsonFileNotFound: message = "Json file not found"; break;
        case eErrorType::eJsonInvalidFormat: message = "Invalid json file"; break;
        case eErrorType::eJsonKeyNotFound: message = "Specified key is not found in json"; break;
        case eErrorType::eJsonEmptyArray: message = "No elements in json array"; break;
        case eErrorType::eNoError: message = "Entry contained an attempt to divide by zero!"; break;
        default: message = ""; break;
        }
    }
};

int main()
{
    try
    {
        //open json file. If file open failed, throw error
        throw eErrorType::eJsonFileNotFound;

        //parse json file. If parsing failed, throw error
        throw eErrorType::eJsonInvalidFormat;

        //check for particular key in the json. If not found, throw error
        throw eErrorType::eJsonKeyNotFound;
    }
    catch (eErrorType errCode)
    {
        Error errObj(errCode);
        std::cout << errObj.getErrMessage() << std::endl;
    }

    return 0;
}

我想提出一些改进建议。有没有更好的方法或基于语言的功能可以实现此目的。

1 个答案:

答案 0 :(得分:3)

对于自定义错误,您可以从std :: exception继承,重写异常方法并实现自己的东西,例如:

#include <exception>    // std::exception

//
// custom exception class
//
    class error final :
        public std::exception
    {
    public:
        error(const char* description, short code = -1) throw() :
            description(description), code(code) { }

        const char* what() const throw() override
        {
            return description;
        }

        short Code() const throw()
        {
            return code;
        }

        error(error&& ref)
            : description(ref.description), code(ref.code) { }

        error& operator=(error&&)
        {
            return *this;
        }

        error(const error& ref)
            : description(ref.description), code(ref.code) { }

    private:
        const char* description;
        const short code;
        error& operator=(const error&) = delete;
    };

定义一个宏以显示发生错误的文件名:

#include <cstring>      // std::strrchr
// Show only file name instead of full path
#define __FILENAME__ (std::strrchr(__FILE__, '\\') ? std::strrchr(__FILE__, '\\') + 1 : __FILE__)

定义通用功能以显示错误(以下实现会显示消息框,但您可以将其重新定义为控制台程序)

#include <string>
#include <windows.h>
#include <codecvt>      // string conversion std::wstring_convert and std::codecvt_utf8

//
// converts string or const char* to wstring
//
std::wstring stringToWstring(const std::string& t_str)
{
    //setup converter
    typedef std::codecvt_utf8<wchar_t> convert_type;
    std::wstring_convert<convert_type, wchar_t> converter;

    //use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
    return converter.from_bytes(t_str);
}

//
// Set error message to your liking using error class
// and show message box, this function is also used to pass in
// std::exception objects
//
template <typename ExceptionClass>
void ShowError(
    HWND hWnd,
    ExceptionClass exception,
    const char* file,
    int line,
    long info = MB_ICONERROR)
{
    std::string error_type = TEXT("Rutime Error");
    std::string error_message = TEXT("File:\t");

#ifdef UNICODE
    error_message.append(stringToWstring(file));
#else
    error_message.append(file);
#endif // UNICODE

    error_message.append(TEXT("\r\nLine:\t"));
    error_message.append(std::to_string(line));
    error_message.append(TEXT("\r\nError:\t"));

#ifdef UNICODE
    error_message.append(stringToWstring(exception.what()));
#else
    error_message.append(exception.what());
#endif // UNICODE

    // Show error message
    MessageBox(hWnd,
        error_message.c_str(),
        error_type.c_str(), static_cast<UINT>(MB_OK | info));
}

然后显示如下错误:

ShowError(nullptr, error("You error message"), __FILENAME__, __LINE__);

对于Win32 / COM错误类型,该函数可以像这样重载:

#include <comdef.h>     // _com_error
#include <windows.h>
#include <string>
//
// Format error code into a string and show message box
// COM and System errors
//
void ShowError(HWND hWnd, const char* file, int line, HRESULT hr = S_OK)
{
    string error_type = TEXT("Rutime Error");
    string error_message = TEXT("File:\t");

#ifdef UNICODE
    error_message.append(stringToWstring(file));
#else
    error_message.append(file);
#endif // UNICODE

    error_message.append(TEXT("\r\nLine:\t"));
    error_message.append(std::to_string(line));
    error_message.append(TEXT("\r\nError:\t"));

    // If HRESULT is omited or S_OK
    // format last error code message
    if (hr == S_OK)
    {
        LPVOID lpBuff = nullptr;

        DWORD dwChars = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM,
            nullptr,
            GetLastError(),
            0,
            reinterpret_cast<LPTSTR>(&lpBuff),
            0,
            nullptr);

        // If the function succeeds, the return value is
        // the number of TCHARs stored in the output buffer
        if (dwChars)
        {
            error_message.append(reinterpret_cast<LPCTSTR>(lpBuff));
        }
        else // If the function fails, the return value is zero
        {
            error_message.append(TEXT("Unknown Error\t"));
            error_message.append(to_string(GetLastError()));
        }

        // Free the buffer allocated by FormatMessage
        LocalFree(lpBuff);
    }
    else // Format com error code into a message
    {
        _com_error err(hr);
        error_message.append(err.ErrorMessage());
    }

    // Play the sound and show error message
    MessageBox(hWnd,
        error_message.c_str(),
        error_type.c_str(), MB_OK | MB_ICONERROR);
}

对于系统错误,该函数的调用略有不同:

ShowError(nullptr, __FILENAME__, __LINE__); // type hresult if needed

修改: 我从项目中复制了代码,目前std::to_string提到的仅适用于ANSI版本,您需要修改ShowError函数以有条件地将std::to_wstring用于unicode。 同样,ShowError函数中的string也是ANSI字符串,如果您不愿意,可以有条件地使用wstring或为字符串定义宏:

#ifdef UNICODE
    typedef std::wstring string;
#else
    typedef std::string string;
#endif // UNICODE

如果需要,也可以to_string使用

// conditionaly use string or wide string
#ifdef UNICODE
#define to_string std::to_wstring
#else
#define to_string std::to_string
#endif // UNICODE

如果您希望避免在每个单独的函数调用中都键入错误消息,则还可以实现enum class代码类型,并将它们作为第二个或第三个附加参数传递给异常类,并实现显示自定义错误代码。

还请注意,ShowError函数可用于catch语句内的std错误,您只需在其中传递std错误对象,例如:

try
{
       // example, or do some heavy memory allocation here to throw
       throw std::bad_alloc;
}
catch(std::bad_alloc& err);
{
       ShowError(nullptr, err, __FILENAME__, __LINE__);
}

可以扩展此方法,以修改功能以同时格式化NTSTATUS消息

有关Win32中可能的错误消息的完整列表,请参见this

有关上述代码中使用的功能的其他信息,请参见以下链接:

FormatMessage功能

GetLastError功能

一些代码已从此站点复制,例如:

Convert to wstring

Show only file name

Format COM Error code