Unicode的例外是什么()
或者,“俄罗斯人如何抛出exception?”
std :: exception的定义是:
namespace std { class exception { public: exception() throw(); exception(const exception&) throw(); exception& operator=(const exception&) throw(); virtual ~exception() throw(); virtual const char* what() const throw(); }; }
deviseexception层次结构的stream行学派是派生自std :: exception:
通常,最好是抛出对象,而不是内置的。 如果可能的话,你应该抛出从std :: exception类派生(最终)的类的实例。 通过让你的exception类inheritance(最终)从标准exception基类,你的生活使用户更容易(他们可以select通过std :: exception捕获大部分东西),再加上你可能提供更多的信息(比如你的特殊exception可能是std :: runtime_error或者其他的).std :: runtime_error或者其他)。
但是面对Unicode,devise一个实现以下两个方面的exception层次似乎是不可能的:
- 最终从std :: exception派生,以便在catch站点使用
- 提供Unicode兼容性,以便诊断不会被切片或乱码
用一个可以用Unicodestring构造的exception类就可以了。 但是标准规定what()必须返回一个const char *,所以在某些时候inputstring必须转换为ASCII。 无论是在构build时还是在调用what()时(如果源string使用不能用7位ASCII表示的字符),都可能无法在不失真的情况下格式化消息。
如何devise一个exception层次结构,将std :: exception派生类与无损Unicode诊断的无缝集成结合起来?
char *不代表ASCII。 您可以使用8位Unicode编码,如UTF-8。 字符也可以是16位或更多,你可以使用UTF-16。
返回UTF-8是一个明显的select。 如果使用您的例外的应用程序使用不同的多字节编码,则可能很难显示string。 (它不知道它是UTF-8,可以吗?)另一方面,对于显示UTF-8string的ISO-8859- * 8bit编码(西欧,西里尔等)将“只”显示一些乱码和你(或你的用户)可能会罚款,如果你不能消除歧义顺便说一句。 一个字符集中的char *和UTF-8。
就个人而言,我认为只有低级别的错误信息应该进入什么()string,我个人认为这些应该是英语无论如何。 (也许结合一些错误号码或什么的。)
我用what()
看到的最糟糕的问题是,在what()消息中包含一些上下文详细信息(例如文件名 )并不罕见。 文件名通常是非 ASCII的,所以你别无select,只能使用UTF-8作为what()
编码。
还要注意,你的exception类(从std :: exception派生)显然可以提供你喜欢的任何访问方法,所以增加一个显式的what_utf8()
或what_utf16()
或what_iso8859_5()
可能是有意义的。
编辑:关于约翰的评论如何返回UTF-8:
如果你有一个const char* what()
函数,这个函数本质上返回一堆字节。 在西欧的Windows平台上,这些字节通常会被编码为Win1252 ,但在俄罗斯的Windows上,它可能是Win1251 。
字节返回意味着什么取决于它们的编码,它们的编码取决于它们“来自哪里”(以及谁在解释它们)。 string文字的编码是在编译时定义的,但在运行时,如何解释它们仍然取决于应用程序。
所以,为了让你的exception返回UTF-8string的what()
(或what_utf8()
),你必须确保:
- input消息到你的exception有一个明确的编码
- 您有一个定义好的用于保存消息的string成员的编码。
-
what()
被调用时what()
你适当地转换编码
例:
struct MyExc : virtual public std::exception { MyExc(const char* msg) : exception(msg) { } std::string what_utf8() { return convert_iso8859_1_to_utf8( what() ); } }; // In a ISO-8859-1 encoded source file const char* my_err_msg = "ISO-8859-1 ... äöüß ..."; ... throw MyExc(my_err_msg); ... catch(MyExc const& e) { std::string iso8859_1_msg = e.what(); std::string utf_msg = e.what_utf8(); ...
转换也可以放在MyExc()的(重载)what()成员函数中, 或者你可以定义exception以获取UTF-8编码的string, 或者你可以转换(从预期的input编码,也许wchar_t / UTF -16)在ctor。
第一个问题是你打算怎么处理what()string?
你打算在某处login信息吗?
如果是这样,你不应该使用what()string的内容,你应该使用该string作为参考来查找正确的本地特定日志消息。 所以对我来说,what()不是用于logging目的(或任何forms的显示)的内容,它是查找实际日志string(可以是任何Unicodestring)的一种方法。
现在; what()string可以包含人类可读的消息,以便开发人员快速debugging(但不需要高度可读的抛光文本)。 结果是没有理由支持比ASCII更多的东西。 遵守KISS原则。
const char *不必指向ASCIIstring; 它可以是多字节编码,如UTF-8。 一种select是使用wcstombs()
和朋友将wstrings转换为string,但在打印之前,可能必须将what()
的结果转换回wstring。 在exception处理程序中,它也涉及到更多的复制和内存分配。
我通常只是定义我自己的基本exception类,它在构造函数中使用wstring而不是string,并从what()
返回const wstring。 这并不是什么大事。 缺乏标准是一个相当大的疏忽。
另一个有效的观点是,例外string不应该呈现给用户,所以本地化他们是没有必要的,所以你不必担心上述任何。
标准没有指定what()返回的string是什么编码,也没有任何事实上的标准。 我只是将其编码为UTF-8,并从我的项目中的()中返回。 当然可能与其他图书馆不兼容。
另请参阅: https : //stackoverflow.com/questions/1049947/should-utf-16-be-considered-有害的为什么UTF-8是不错的select。
绝对最小每个软件开发人员肯定,积极必须知道Unicode和字符集(没有借口!)通过Joel Spolsky
编辑:作CW,评论者可以编辑为什么这个链接是相关的,如果他们希望
什么()通常不意味着向用户显示消息。 除此之外,它返回的文本是不可本地化的(即使它是Unicode)。 我只是使用what()来向开发者显示一些有价值的东西(比如引发exception的地方的源文件和行号),对于这种文本,ASCII通常是绰绰有余的。
在error handling中添加unicode是更好的方法:
try { // some code } catch (std::exception & ex) { report_problem(ex.what()) }
和:
void report_problem(char const * const) { // here we can convert char to wchar_t or do some more else // log it, save to file or message to user }