4

关于跨平台Unicode字符串使用的主题有无数的讨论线程,但似乎有广泛的意见,没有解决一些在我正在从事的特定项目中一直困扰我的具体问题:

我有一个可以追溯到近 20 年的大型跨平台 C++ 代码库。它包含各种字符串实现方式的大杂烩,包括:

  • char*
  • 帕斯卡风格的字符串
  • std::string
  • 几个具有重叠功能的自定义跨平台类
  • CFString
  • 各种常量字符串

该代码库正在重写以完全使用 Unicode 字符串并实现强大的 MVC 架构,希望该模型将完全可移植(Mac OS / IOS / Android / Windows 7 & 8 / Unix)。

虽然持久性数据被编写为 XML/UTF-8,但在运行时对象中的字符串使用方面存在一些困境:

  1. 我想创建一个干净地隐藏存储、分配和常见字符串操作的实现的类。通过 C++ 运算符和赋值重载的奇迹,我希望能够替换一个类实例来替换函数可以接受的所有不同的字符串参数。这将允许代码库的增量转换。

  2. 我们一直在扫描/解析/分析字符串,我担心对持久对象使用严格的 UTF-8 底层实现可能会出现性能问题。如果不是,那么在微软的 VC++ 和 GNU 的 G++ 中发现的现代 std::string 会是一个简单的底层实现吗?

  3. Mac OS / IOS 版本最终需要将其字符串“转换”为 CFString。CF 功能丰富且高度优化。我认为通过为 CF 提供缓冲区(例如,CFStringCreateWithCharactersNoCopyCFStringCreateMutableWithExternalCharactersNoCopy)让我自己的类创建 CFStrings 将是一个很好的策略。似乎这可以减少从模型中获取数据后 CFString 通常需要的转换/分配量——尽管可能在适当的 MVC 实现中,控制器/视图不应该访问模型拥有的实际字符串?

  4. C++ 11 是否会改变这些跨平台字符串问题的情况?

我猜想这些问题早就应该解决了——但是从查看本网站(和其他网站)上的回复来看,我看不出它已经解决了。

4

1 回答 1

4

我想创建一个干净地隐藏存储、分配和常见字符串操作的实现的类。通过 C++ 运算符和赋值重载的奇迹,我希望能够替换一个类实例来替换函数可以接受的所有不同的字符串参数。这将允许代码库的增量转换。

听起来像std::string添加了演员运算符 to const char*,因此您不必调用c_str(). 这意味着您必须使用charUTF-8 进行存储,而不是 UTF-16 或类似的。

我们一直在扫描/解析/分析字符串,我担心对持久对象使用严格的 UTF-8 底层实现可能会出现性能问题。如果不是,那么std::string在 Microsoft 的 VC++ 和 GNU 的 G++ 中发现的现代会是一个简单的底层实现吗?

这取决于其他几个因素。一方面,如果您的输入包含大量非 ascii 数据并且您必须一次分析一个代码点,则 UTF-8可能效率低下。在这种情况下,UTF-16 甚至 UTF-32 可能更合理,因为从多个字符串元素重新组合代码点时不会有那么多大小写区别。另一方面,性能很大程度上取决于您是否可以通过引用传递字符串或必须创建副本,尤其是在调用函数时。因此,为了避免过多的副本,可能需要对现有代码库进行一些修改。

Mac OS / IOS 版本最终需要将其字符串“转换”为 CFString。CF 功能丰富且高度优化。我认为通过为 CF 提供缓冲区(例如,CFStringCreateWithCharactersNoCopy 或 CFStringCreateMutableWithExternalCharactersNoCopy)让我自己的类创建 CFStrings 是一个很好的策略。似乎这可以减少从模型中获取数据后 CFString 通常需要的转换/分配量——尽管可能在适当的 MVC 实现中,控制器/视图不应该访问模型拥有的实际字符串?

当您在不复制数据缓冲区的情况下创建字符串时,您必须确保缓冲区在访问字符串时一直存在。这在某些情况下可能是正确的,但并非全部如此。一般来说,这些问题与char*由 a 支持的问题非常相似std::string,这就是为什么c_str()是显式函数调用而不仅仅是自动转换的原因。通过进行这样的转换,您必须保证原始对象保持分配状态。一般来说,我会传递const std::string&给视图,因此它们不会意外更改模型拥有的字符串。如果他们需要保留或修改字符串,他们将不得不复制它。

C++ 11 是否会改变这些跨平台字符串问题的情况?

C++ 11 提供了许多新的智能指针实现,允许您更好地控制字符串对象保持分配的时间。因此,例如,您可以使用 ashared_prt<string>作为类的数据存储,以获得自动引用计数和字符串的释放。这将为您提供更高级别的抽象,但可能与您当前的代码库所做的相距甚远,因此我不确定这是否会使您的移植更容易。

于 2013-01-07T06:07:43.237 回答