为什么面对std :: string会有这么多的字符串类?


56

在我看来,许多更大的C ++库最终都创建了自己的字符串类型。在客户端代码,你要么必须使用从库中一个(QStringCStringfbstring等,我相信任何人都可以仅举几例)或保持标准型和一之间进行转换的库使用(其中大部分时间涉及至少一份)。

那么,是否存在某种特定的功能缺陷或某些错误之处std::string(就像auto_ptr语义不好一样)?它在C ++ 11中有变化吗?


32
它被称为“此处未发明综合征”。
Cat Plus Plus

10
@CatPlusPlus QString和CString都早于std :: string。

8
@Cat Plus Plus:这种综合症似乎并不影响Java String类。
Giorgio

20
@ Giorgio:Java程序员正忙于为语言缺陷发明解决方法,以免担心字符串类(顺便说一下,Android重新发明了String)。
Cat Plus Plus

9
@Giorgio:这可能是因为Java的硬编码语法支持java.lang.String(缺少运算符重载等)会使使用其他任何内容变得很痛苦。
机械蜗牛

Answers:


57

大多数较大的C ++库都是在std::string标准化之前启动的。其他功能包括后来被标准化或尚未标准化的其他功能,例如对UTF-8的支持以及编码之间的转换。

如果这些库在今天实现,它们可能会选择编写对std::string实例进行操作的函数和迭代器。


5
自C ++ 98起,对UTF-8的支持已标准化。以这种不便且部分实现的定义方式,几乎没有人可以使用它
AProgrammer,2012年

9
@AProgrammer:char确保足够大以容纳任何UTF-8代码点。AFAIK,这是C ++ 98提供的唯一“支持”。
Ben Voigt 2012年

4
@AProgrammer:这种支持真的没有用。
DeadMG 2012年

4
@AProgrammer该区域设置可以说是坏,因为wchar_t不是大到足以代表所有Unicode代码点。此外,关于UTF-16的整个讨论都被认为是有害的,在该论点上,非常有说服力的论点认为 应该只使用UTF-8
Konrad Rudolph

6
@KonradRudolph,不是在此处损坏的语言环境系统(wchar_t的定义“对于任何受支持的字符集而言足够宽”);承诺使用16位wchar_t的系统确实确实承诺不支持Unicode。好吧,罪魁祸首是Unicode,它首先保证它永远不会使用需要超过16位的代码点,然后保证系统使用16位的wchar_t,然后进行Unicode转换就需要超过16位。
AProgrammer 2012年

39

字符串是C ++的最大尴尬。

在最初的15年中,您根本不提供字符串类-强制每个平台上的每个编译器和每个用户创建自己的字符串类。

然后,对于应该是完整的字符串操作API还是仅仅是STL char容器,您会产生一些困惑,因为有些算法会复制std :: Vector上的算法或其他算法。

在明显的字符串操作(例如replace()或mid())涉及如此多的迭代器的情况下,您需要引入新的'auto'关键字以使语句适合单个页面,并导致大多数人放弃整个语言。

然后,您有了unicode'support'和std :: wstring,这只是个错误.....

<离开>谢谢-我现在感觉好多了。


12
@DeadMG-是的,它是在1998年标准化的,即发明15年后,甚至是MSFT使用6年之后。是的,迭代器是使数组和列表看起来相同的有用方法,您认为它们是进行字符串操作的明显方法吗?
马丁·贝克特

3
带类的C于1983年发明。不是C ++。唯一的标准库是由标准确定的库,这很奇怪,只有拥有标准后才能发生,因此任何标准库的最早日期是1998年。迭代器可以被认为与索引完全相等,但类型强。我完全同意,与范围相比,迭代器很烂,但这并不是真正针对的std::string。1983年缺少String类并不能证明现在有更多的此类。
DeadMG 2012年

8
我以为iostream是C ++的大尴尬...
Doug T.

18
@DeadMG在1998年之前,人们一直使用“ C ++”之类的东西。我在1985年使用“ C ++”之类的东西编写了我的第一个程序。如果您想说这不是“真正的” C ++,那很好,但是在此之前,我们正在编写代码,并且不得不从某个地方获取字符串类。一旦有了这些遗留代码库,我们就无法准确地将它们扔掉或在获得标准后从头重写。现在应该发生的是,cfront应该带有一个字符串类。
对机器人

8
@DeadMG-如果在获得ISO证书之前没有人使用某种语言,则将永远不会使用任何语言,因为它将永远不会达到ISO。x86汇编器没有ISO标准,但我很高兴使用该平台
Martin Beckett 2012年

32

实际上...存在一些问题std::string,是的,它在C ++ 11中会变得更好一些,但请不要超越自己。

QString并且CString库的一部分,因此它们在C ++标准化之前就已经存在(很像SGI STL)。因此,他们必须创建一个类。

fbstring解决非常具体的性能问题。该标准规定了一个接口,算法的复杂性保证了最低限度,但是无论最终是否快速,这都是实施质量的细节。fbstring具有特定的优化(find例如与存储相关的或更快的)。

其他未引起关注的问题(en vrac):

  • 在C ++ 03中,不强制要求存储必须是连续的,这可能会使与C的互操作性变得困难。C ++ 11修复了此问题。
  • std::string 没有编码,并且没有UTF-8的特殊代码,很容易在其中存储UTF-8字符串并无意间破坏它
  • std::string接口是ated肿的,许多方法本可以实现为自由功能,并且许多方法被复制以符合基于索引的接口和基于迭代器的接口。

5
有关#1-C ++ 03 21.3.6 / 1保证c_str()返回指向连续存储的指针,该指针提供了一些C的互操作性。但是,您不能修改指向的数据。典型的解决方法包括使用vector<char>
John Dibling 2012年

@JohnDibling:是的,还有另一个限制:它可能会在新分配的存储中产生一个副本(标准并未说不会)。当然,C ++ 11也不会阻止复制,但是由于您可以简单地进行复制&s[0]就不再重要了:)
Matthieu M.12年

1
@MatthieuM .:通过获得的指针&s[0]可能未指向以NUL终止的字符串(除非c_str()自上次修改以来已被调用)。
Ben Voigt 2012年

2
@Matthieu:不允许使用另一个缓冲区。“ c_str()返回:这样的指针pp + i == &operator[](i)用于iin 中的每个[0,size()]
Ben Voigt 2012年

3
还应该指出的是,没有人在头脑中不再使用MFC,因此很难说CString是现代C ++中的字符串类。
DeadMG 2012年

7

除了这里发布的原因之外,还有另一种二进制兼容性。图书馆的作者无法控制std::string您使用的是哪种实现,以及它是否具有与他们相同的内存布局。

std::string是一个模板,因此其实现是从本地STL标头中获取的。现在,假设您在本地使用一些性能经过优化的STL版本,该版本与标准完全兼容。例如,您可能选择在每个静态缓冲区中插入静态缓冲区std::string以减少动态分配和高速缓存未命中的次数。结果,实现的内存布局和/或大小与库的不同。

如果仅布局不同,std::string则从库传递到客户端的实例上的某些成员函数调用可能会失败,反之则可能失败,具体取决于转移的成员。

如果大小也不同std::string,则在库和客户端代码中进行检查时,所有具有成员的库类型都将具有不同的sizeof。跟随std::string成员的数据成员的偏移量也将偏移,并且从客户端调用的任何直接访问/内联访问器都将返回垃圾,尽管在调试库本身时“看起来不错”。

底线-如果库和客户端代码std::string再次编译为不同版本,则它们将链接得很好,但是可能会导致一些令人讨厌且难以理解的错误。如果更改std::string实现,则必须重新编译STL中公开成员的所有库,以匹配客户端的std::string布局。而且由于程序员希望他们的库更强大,因此几乎看不到std::string任何地方公开的内容。

公平地说,这适用于所有STL类型。IIRC他们没有标准化的内存布局。


2
您必须是* nix程序员。C ++二进制兼容性并非在所有平台上都相等,特别是在Windows上,包含数据成员的类在编译器之间可移植。
Ben Voigt 2012年

(我的意思是除POD类型外,甚至还需要明确的包装要求)
Ben Voigt 2012年

1
感谢您的输入,尽管我没有在说其他编译器,但我在说不同的STL。
gwiazdorrr 2012年

1
+1:ABI是推出自己版本的编译器提供的类的重要原因。就此而言,我希望这是公认的答案。
Thomas Eding

6

这个问题有很多答案,但是这里有一些:

  1. 遗产。在存在std :: string之前,已编写了许多字符串库和类。

  2. 为了与C中的代码兼容。库std :: string是C ++,其中还有其他与C和C ++一起使用的字符串库。

  3. 避免动态分配。std :: string库使用动态分配,可能不适合嵌入式系统,中断或实时相关代码或低级功能。

  4. 模板。std :: string库基于模板。直到不久以前,许多C ++编译器的性能还很差,甚至还没有足够的模板支持。不幸的是,我在一个使用大量自定义工具的行业中工作,而来自该行业主要参与者的我们的工具链之一并没有“正式”地100%支持C ++(有错误的东西是模板等)。

可能还有许多更正当的理由。


2
“最近刚好”的意思是“距Visual Studio都已经有十多年的合理支持了”。
DeadMG 2012年

@DeadMG-Visual Studio不是世界上唯一的不兼容编译器。我从事视频游戏工作,我们经常为未发布的硬件平台(在控制台周期中每隔几年或出现新硬件出现的情况下)开发自定义编译器。“最近刚好”表示今天-现在某些编译器不很好地支持模板。在不违反NDA的前提下,我不能一概而论,但是我目前正在使用自定义工具链的平台,该平台将C ++支持(尤其是模板合规性)视为“实验性”。
2012年

4

主要是关于Unicode。对Unicode的标准支持充其量是极差的,每个人都有自己的Unicode需求。例如,ICU支持您可能想要的所有Unicode功能,在您可能想像到的最令人讨厌的自动从Java生成接口的背后,如果在Unix上使用UTF-16,则可能不是您的想法美好时光。

此外,许多人需要不同级别的Unicode支持-并非每个人都需要复杂的文本布局API等。因此,很容易看出为什么存在大量的字符串类-标准类非常糟糕,每个人都有与新类不同的需求,没有人设法创建一个可以通过令人愉悦的界面执行许多Unicode支持跨平台的类。

在我看来,这主要是C ++委员会在1998或2003年没有正确提供对Unicode的支持的错,也许这是可以理解的,但是在C ++ 11中却不是。希望在C ++ 17中它们会做得更好。


您好,C ++ 20在这里,您猜想Unicode支持发生了什么?
路人

-4

这是因为每个程序员都有一些要证明的事情,并且感到有必要为自己的一个很棒的函数创建自己的很棒的,更快的字符串类。根据我的经验,它通常是多余的,并导致各种额外的字符串转换。


7
如果确实如此,那么我希望看到类似数量的String实现在Java之类的语言中一直存在良好的实现。
Bill K

@BillK Java String是最终的,因此您必须在其他地方添加新功能。

我的观点是,即使是最终的结论,在20年中我从未见过有人编写过自定义字符串实现(嗯,我确实试图提高字符串连接性能,但事实证明Java在string + string方面比您聪明得多) d想象)
Bill K

2
@比尔:这可能与另一种文化有关。C ++吸引了那些想了解底层细节的人。Java吸引了那些只想使用别人的构件来完成工作的人。(请注意,这并不是有关选择使用哪种语言的任何特定个人的声明,而是有关语言的各自设计目标和文化的声明)
Ben Voigt 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.