c ++异常类设计 [英] c++ Exception Class Design

查看:156
本文介绍了c ++异常类设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于一组异常类,什么是好的设计?我看到各种各样的东西围绕什么异常类应该和不应该做,但不是一个简单的设计,这是容易使用和扩展,这些事情。

What is a good design for a set of exception classes? I see all sorts of stuff around about what exception classes should and shouldn't do, but not a simple design which is easy to use and extend that does those things.


  1. 异常类不应该抛出异常,因为这可能直接导致进程的终止,没有任何机会记录错误等。

  2. 它需要可以得到一个用户友好的字符串,最好是本地化到他们的语言,这样有一些东西在应用程序终止之前告诉他们,如果它无法从错误中恢复。

  3. 它需要可能添加信息作为堆栈展开,例如,如果xml解析器无法解析输入流,能够添加源是来自文件,或通过网络等。

  4. 异常处理程序需要轻松访问处理异常所需的信息

  5. 将格式化的异常信息写入日志文件(英语,因此此处没有翻译)。

  1. The exception classes shouldn't throw exceptions, since this could lead straight to the termination of the process without any chance to log the error etc.
  2. It needs to be possible to get a user friendly string, preferable localised to their language, so that there's something to tell them before the application terminates itself if it cant recover from an error.
  3. It needs to be possible to add information as the stack unwinds, eg if an xml parser fails to parse an input stream, to be able to add that the source was from a file, or over the network, etc.
  4. Exception handlers need easy access to the information they need to handle the exception
  5. Write formatted exception information to a log file (In English, so no translations here).

获得1和4一起工作是我遇到的最大的问题,因为任何格式化和文件输出方法都可能失败。

Getting 1 and 4 to work together is the biggest issue I'm having, since any formatting and file output methods could potentially fail.

编辑:
所以看过几个类中的异常类,以及在Neil链接到的问题中,似乎普遍的做法是完全忽略项目1(因此这对我来说似乎是一个不太好的想法。

So having looked at exception classes in several classes, and also in the question Neil linked to, it seems to be common practice to just completely ignore item 1 (and thus the boost recomendations), which seems to be a rather bad idea to me.

无论如何我认为id也post后的异常类,我在想使用。

Anyway I thought id also post the exception class I'm thinking of using.

class Exception : public std::exception
{
public:
    //enum for each exception type, which can also be used to determin
    //exception class, useful for logging or other localisation methods
    //for generating a message of some sort.
    enum ExceptionType
    {
        //shouldnt ever be thrown
        UNKNOWN_EXCEPTION = 0,
        //same as above but has a string that may provide some info
        UNKNOWN_EXCEPTION_STR,
        //eg file not found
        FILE_OPEN_ERROR,
        //lexical cast type error
        TYPE_PARSE_ERROR,
        //NOTE: in many cases functions only check and throw this in debug
        INVALID_ARG,
        //an error occured while trying to parse data from a file
        FILE_PARSE_ERROR,
    }
    virtual ExceptionType getExceptionType()const throw()
    {
        return UNKNOWN_EXCEPTION;
    }
    virtual const char* what()throw(){return "UNKNOWN_EXCEPTION";}
};
class FileOpenError : public Exception
{
public:
    enum Reason
    {
        FILE_NOT_FOUND,
        LOCKED,
        DOES_NOT_EXIST,
        ACCESS_DENIED
    };
    FileOpenError(Reason reason, const char *file, const char *dir)throw();
    Reason getReason()const throw();
    const char* getFile()const throw();
    const char* getDir ()const throw();
private:
    Reason reason;
    static const unsigned FILE_LEN = 256;
    static const unsigned DIR_LEN  = 256;
    char file[FILE_LEN], dir[DIR_LEN];
};

点1是由于所有字符串都是通过复制到一个内部固定大小的缓冲区来处理的需要,但总是null终止)。

Point 1 is addressed since all strings are handled by copying to an internal, fixed size buffer (truncating if needed, but always null terminated).

虽然这不涉及第3点,但我认为这一点很可能在真实世界有限的使用,

Although that doesn't address point 3, however I think that point is most likely of limited use in the real world anyway, and could most likely be addressed by throwing a new exception if needed.

推荐答案

使用浅层次的异常类。使层次结构过深会增加比值的复杂性。

Use a shallow hierarchy of exception classes. Making the hierarchy too deep adds more complexity than value.

从std :: exception(或其他标准异常,如std :: runtime_error)派生异常类。这允许在顶层的通用异常处理程序处理任何异常。例如,可能有一个异常处理程序记录错误。

Derive your exception classes from std::exception (or one of the other standard exceptions like std::runtime_error). This allows generic exception handlers at the top level to deal with any exceptions you don't. For example, there might be an exception handler that logs errors.

如果这是一个特定的库或模块,你可能需要一个特定于你的模块从一个标准的异常类)。调用者可能会决定从你的模块中捕获任何东西。

If this is for a particular library or module, you might want a base specific to your module (still derived from one of the standard exception classes). Callers might decide to catch anything from your module this way.

我不会生成太多的异常类。您可以将大量关于异常的详细信息包含在类中,因此您不一定需要为每种错误都创建一个唯一的异常类。另一方面,你需要唯一的类来处理你所期望的错误。如果你是一个解析器,你可能有一个单一的syntax_error异常,成员描述问题的详细信息,而不是一堆专业的不同类型的语法错误。

I wouldn't make too many exception classes. You can pack a lot of detail about the exception into the class, so you don't necessarily need to make a unique exception class for each kind of error. On the other hand, you do want unique classes for errors you expect to handle. If you're making a parser, you might have a single syntax_error exception with members that describe the details of the problem rather than a bunch of specialty ones for different types of syntax errors.

异常中的字符串用于调试。您不应在用户界面中使用它们。您希望将UI和逻辑保持尽可能独立,以支持翻译为其他语言。

The strings in the exceptions are there for debugging. You shouldn't use them in the user interface. You want to keep UI and logic as separate as possible, to enable things like translation to other languages.

您的异常类可以有额外的字段,其中包含有关问题的详细信息。例如,syntax_error异常可以具有源文件名,行号等。尽可能地,坚持这些字段的基本类型,以减少构造或复制异常以触发另一个异常的机会。例如,如果您必须在异常中存储文件名,您可能需要一个固定长度的纯字符数组,而不是一个std :: string。 std :: exception的典型实现使用malloc动态分配原因字符串。如果malloc失败,他们将牺牲原因字符串,而不是抛出嵌套异常或崩溃。

Your exception classes can have extra fields with details about the problem. For example, a syntax_error exception could have the source file name, line number, etc. As much as possible, stick to basic types for these fields to reduce the chance of constructing or copying the exception to trigger another exception. For example, if you have to store a file name in the exception, you might want a plain character array of fixed length, rather than a std::string. Typical implementations of std::exception dynamically allocate the reason string using malloc. If the malloc fails, they will sacrifice the reason string rather than throw a nested exception or crashing.

C ++中的异常应该用于异常条件。所以解析的例子可能不是好的。解析文件时遇到的语法错误可能不够特殊,无法保证由异常处理。我会说,如果程序可能无法继续,除非条件明确处理,例外。因此,大多数内存分配失败是例外,但来自用户的错误输入可能不是。

Exceptions in C++ should be for "exceptional" conditions. So the parsing examples might not be good ones. A syntax error encountered while parsing a file might not be special enough to warrant being handled by exceptions. I'd say something is exceptional if the program probably cannot continue unless the condition is explicitly handled. Thus, most memory allocation failures are exceptional, but bad input from a user probably isn't.

这篇关于c ++异常类设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆