c ++exception类devise
对于一组exception类,一个好的devise是什么? 我看到围绕什么exception类应该和不应该做什么的各种东西,但不是一个简单的devise,易于使用和扩展,做这些事情。
- exception类不应该抛出exception,因为这会直接导致进程终止,而没有任何logging错误的机会。
- 它需要能够得到一个用户友好的string,最好是本地化到他们的语言,所以如果它不能从错误中恢复,那么在应用程序终止之前有一些东西要告诉他们。
- 在堆栈展开时,需要添加信息,例如,如果xmlparsing器无法parsinginputstream,可以添加源文件或networking等。
- exception处理程序需要轻松访问处理exception所需的信息
- 将格式化的exception信息写入日志文件(英文,所以在这里没有翻译)。
让1和4一起工作是我遇到的最大的问题,因为任何格式化和文件输出方法都可能失败。
编辑:所以看了几个类的exception类,并在尼尔链接到的问题,似乎是普遍的做法,完全忽略项目1(从而推动推荐),这似乎是一个相当糟糕的主意我。
无论如何,我想id也张贴我正在考虑使用的exception类。
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]; };
因为所有的string都是通过复制到一个内部固定大小的缓冲区(如果需要截断,但总是以null结尾)来处理,所以解决了点1问题。
虽然这不能解决第3点,但是我认为这一点在现实世界中最有可能是有限的使用,而且如果需要的话,最有可能通过抛出一个新的exception来解决。
使用浅层次的exception类。 使层次太深,增加了复杂性而不是价值。
从std :: exception(或其他标准exception之一,如std :: runtime_error)派生你的exception类。 这允许顶层的通用exception处理程序处理任何exception。 例如,可能有一个logging错误的exception处理程序。
如果这是针对某个特定的库或模块,则可能需要一个特定于您的模块的基础(仍然来自其中一个标准exception类)。 呼叫者可能决定以这种方式从模块中捕捉任何东西。
我不会做太多的exception类。 你可以在类中包含很多关于exception的细节,所以你不一定需要为每种types的错误创build一个唯一的exception类。 另一方面,你确实需要独特的类来处理你想要处理的错误。 如果你正在创build一个parsing器,那么你可能会遇到一个syntax_errorexception,其中的成员描述了这个问题的细节,而不是针对不同types的语法错误。
例外的string用于debugging。 你不应该在用户界面中使用它们。 你想保持UI和逻辑尽可能分开,以使诸如翻译成其他语言的东西。
你的exception类可以有额外的领域与问题的细节。 例如,syntax_errorexception可能包含源文件名,行号等。尽可能地坚持这些字段的基本types,以减less构造或复制exception的机会以触发另一个exception。 例如,如果必须在exception中存储文件名,则可能需要一个固定长度的普通字符数组,而不是std :: string。 std :: exception的典型实现使用mallocdynamic分配原因string。 如果malloc失败,他们将牺牲原因string,而不是抛出嵌套exception或崩溃。
C ++中的例外应该是“特殊”的条件。 所以parsing的例子可能不是很好的例子。 parsing文件时遇到的语法错误可能不足以保证被exception处理。 如果程序可能无法继续,除非条件被明确处理,否则我会说一些例外。 因此,大多数内存分配失败是例外的,但是来自用户的错误input可能不是。
使用虚拟inheritance 。 这个见解是由于安德鲁·柯尼格(Andrew Koenig) 在exception的基类中使用虚拟inheritance可以防止catch-site引起歧义问题,以防有人抛出一个由多个基类共同派生的exception。
其他同样有用的build议,在推动网站
2:不,你不应该混合用户界面(=本地化的消息)与程序逻辑。 当应用程序意识到无法处理问题时,应该在外部进行与用户的通信。 在例外情况下的大部分信息都是太多的实施细节,无论如何都要向用户展示。
3:使用boost.exception
5:不要这样做。 请参阅2.日志决定应始终在error handling站点。
不要只使用一种types的exception。 使用足够的types,以便应用程序可以为每种需要的错误恢复使用单独的catch处理程序
与exception类层次结构的devise没有直接关系,但是重要的(并且与使用这些exception有关)是,你通常应该抛出价值并且通过引用来捕获。
这样可以避免与pipe理抛出的exception(如果抛出指针)和潜在的对象分割(如果通过值捕获exception)相关的问题。
一个好的devise是不要创build一组exception类 – 只要根据std :: exception创build一个库。
添加信息相当简单:
try { ... } catch( const MyEx & ex ) { throw MyEx( ex.what() + " more local info here" ); }
exception处理程序拥有所需的信息,因为它们是exception处理程序 – 只有try块中的函数才会导致exception,所以处理程序只需要考虑这些错误。 而不是你真的不应该使用exception来处理一般的错误。
基本上,exception应该尽可能简单 – 有点像日志文件,它们应该没有直接的联系。
我曾经问过这个问题,但我现在找不到。