近两年来在写C++的运行时环境,反射、运行时类型信息、内存管理、并行、字符串、协程、ORM等等,基本上重写了一套标准库以及运行库。对于在c++下使用字符串,深有体会。一开始呕心沥血,殚精竭虑,支持多种编码方式(Utf8、Utf7、GB2312、Utf16LE,Utf16BE等)的字符串类型,以及在此之上的对这些字符串提供格式化、字符串解析、json、xml、文件读写BOM等等功能,必须承认,大C++真是变态,像是这样变态无聊的概念都可以支持,还可以实现得很好,用起来确实也方便。可是,每次面临字符串操作的时候,都会心里发毛,都会嘀咕此时此刻,纠结的是哪门子的编码,也搞得很多代码必须以template的形式,放在头文件上,不放在头文件,就必须抽象出来一个通用的动态字符串类型,代表任意编码的一种字符串类型,代码里面引入各种各样臆造的复杂性。终于受不了啦,最后搞成统一用utf8编码,重构了几千行代码(十几个文件),然后,整个字符串世界终于清静了,接口api设计什么的,也一下子清爽了很多。整个程序内部,就应该只使用同一种编码的字符串。stl的带有多个模板的string设计,就是无病呻吟,画蛇添足。
为什么选择Utf8编码,首先,非unicode编码的字符串是不能考虑的;其次,utf16也是变长的编码方式,而且还有大小端的区别,所以也不能考虑;utf32又太占用内存了。想来想去,终于下定决心,utf8简直就是唯一的选择了。虽然可能有这样那样的小问题,比如说,纯中文文本,utf8占用多50%内存(相比于Utf16),windows下utf8有点不友好。但其实都不是问题,也都可以解决。比如说,windows下,所有的涉及字符串与系统的api交互,先临时转换成utf16,然后再调用api。api的返回结果为utf16,再转换为utf8。好像有一点性能上的损失,其实没啥大不了的。windows对于多字节也是这样支持的,完全就感受不到性能上的影响。总之,utf8简直就是程序处理的唯一字符串编码。
吐槽一下std的字符串,以及与此相关的一切概念,iostream,locale等等东西,垃圾设计的典范。接口不友好,功能弱,而且还性能差,更关键的是其抽象上的泄漏。一整天就只会在引用计数,写时复制,短字符串优化上做文章,时间精力都不用在刀刃上。C++17终于引入string_view的类型,情况稍微有些改善。由于字符串使用上不方便,也因此损失了一大片的用户,阵地一再失守。整体上讲,stl的设计,自然是有精心的考虑,但是,作出这些抽象的标准会上一大群的老爷子们,大概率上讲,应该是没有用stl正儿八经地开发工业级上的代码,臆造抽象,顾虑太多,表面上看起来好像是那么一回事,真正用起来的时候,就不太对劲,会有这样那样的不足,很不方便。
简单说一下U8String的设计思路。U8String用以管理字符串编码缓存的生命周期,追加缩短替换字符串,支持通过下标可以读取字节char,但是不支持将字节写入到某个索引上的位置,当然支持往字符串中插入unicode编码的字符。至于字符串的比较、查找、Trim、截取子字符串这些常用操作,就全部压在U8View上。如果U8String要使用这些,要先通过view的函数,获取自己字节缓存下的视图。U8View表示一段连续的字符编码内存,U8View的任意一部分也是U8View,不要求以0结束。只要求U8View的生存周期不能比其宿主(U8String,字符数组,U8原生字符串)长命。事实上,很多api的字符串参数,其实只是要求为U8View就行了,不需要是什么const string&类型。此外,还提供U8PointPtr的指针类型,用以遍历U8View,其取值为unicode编码值,也就是wchar_t类型。另外,既然有U8View,自然也就有ArrayView,代表连续内存块的任意类型。
自然,库中必须提供格式化Fmt以及解析字符串Scanf的函数。StrFmt用以生成新的U8String,而Fmt格式化函数中传入字符串的话,就将格式化结果追加到字符串后面。Fmt可以格式化数据到控制台,文本文件,日志等等输出结果上。StrFmt的实现只是简单地调用Fmt并返回U8String。有了Fmt和Scanf,操作字符串就很方便很灵活了,同时也消除很多很多有关字符串相关的处理函数。Fmt不仅仅能格式化基本类型,自定义类型,还能格式化数组,vector,list,pair,tuple等模板类型的数据。库中也提供了类似于iostream重载<<和>>的操作符。大C++提高的feature,造出来的string类型,使用上的方便,一点都不逊色于其他任何语言的原生string类型。当然,std的那个string,简直就是废物。
不管怎么说,本人还是很喜欢C++的,用c++写代码很舒畅,可比用C#、haskell、lisp、scala时要开心很多。C++发展到C++11,基本功能也都完备了,当然,C++14、C++17自然功能更加强大,特别是实现模板库的时候,就更方便了,也确实很吸引人。自然,C++也非十全十美,也有很多的不足,比如不能自定义操作符,不提供非侵入式的成员函数,缺乏延迟求值的语言机制,引用的修改绑定(只要不绑定到nullptr就好了),成员函数指针的无端限制。但是,世界上又哪里存在完美的language呢,特别是对于这种直接操纵内存的底层语言来说。至于rust,叫嚣着要取代c++,就它那副特性,还远着呢。