不可变字符串vs std :: string

时间:2010-05-26 20:05:57

标签: c++ string immutability

我最近一直在阅读有关不可变字符串Why can't strings be mutable in Java and .NET?Why .NET String is immutable?以及有关为什么D选择不可变字符串的一些内容。似乎有很多好处。

  • 简单线程安全
  • 更安全
  • 在大多数用例中,内存效率更高。
  • 便宜的子串(标记化和切片)

更不用说大多数新语言都有不可变的字符串,D2.0,Java,C#,Python等。

C ++会从不可变字符串中受益吗?

是否有可能在c ++(或c ++ 0x)中实现具有所有这些优点的不可变字符串类?


更新

对不可变字符串const_stringfix_str进行了两次尝试。五年内都没有更新。它们甚至被使用过吗?为什么const_string没有进入boost?

11 个答案:

答案 0 :(得分:44)

我发现此帖子中的大多数人并不真正理解immutable_string是什么。它不仅仅是关于常数。 immutable_string的真正强大之处在于性能(即使在单线程程序中)和内存使用情况。

想象一下,如果所有字符串都是不可变的,并且所有字符串都实现为

class string {
    char* _head ;
    size_t _len ;
} ;

我们如何实现sub-str操作?我们不需要复制任何字符。我们所要做的就是分配_head_len。然后子字符串与源字符串共享相同的内存段。

当然,我们不能仅使用两个数据成员实现immutable_string。实际实现可能需要引用计数(或飞加权)内存块。喜欢这个

class immutable_string {
    boost::fly_weight<std::string> _s ;
    char* _head ;
    size_t _len ;
} ;

在大多数情况下,内存和性能都会比传统字符串更好,特别是当你知道自己在做什么时。

当然C ++可以从不可变的字符串中受益,并且拥有一个很好。我查看了Cubbi提到的boost::const_stringfix_str。这些应该是我所说的。

答案 1 :(得分:23)

作为意见:

  • 是的,我非常喜欢C ++的不可变字符串库。
  • 不,我不希望std :: string是不可变的。

真的值得做(作为标准库功能)吗?我会说不。 const的使用为您提供了本地不可变的字符串,系统编程语言的基本特性意味着您确实需要可变的字符串。

答案 2 :(得分:9)

我的结论是C ++不需要不可变模式,因为它具有const语义。

在Java中,如果您有一个Person类并且使用String name方法返回该人员的getName(),则您唯一的保护是不可变模式。如果它不存在,那么你需要整天clone()你的字符串(因为你必须处理非典型值对象的数据成员,但仍然需要保护)。

在C ++中,您有const std::string& getName() const。因此,您可以将SomeFunction(person.getName())写为void SomeFunction(const std::string& subject)

  • 没有发生复制
  • 如果有人想要复制,他可以自由地复制
  • 技术适用于所有数据类型,而不仅仅是字符串

答案 3 :(得分:3)

你当然不是唯一一个那样的人。事实上,Maxim Yegorushkin有一个const_string库,它似乎已被写入包含在boost中。这是罗兰·皮宾格(Roland Pibinger)的一个小型图书馆fix_str。我不确定在运行时完整的字符串实习是多么棘手,但大多数优点在必要时都可以实现。

答案 4 :(得分:3)

我认为这里没有明确的答案。它是主观的 - 如果不是因为个人品味,那至少是因为最经常处理的代码类型。 (仍然是一个有价值的问题。)

当内存很便宜时,不可变字符串很棒 - 当开发C ++时,这种情况并非如此,并且在C ++所针对的所有平台上都不是这样。 (OTOH在更有限的平台上C似乎比C ++更常见,所以这个论点很弱。)

您可以在C ++中创建一个不可变的字符串类,并且可以使它与std::string基本兼容 - 但是在与具有专用优化和语言功能的内置字符串类进行比较时,您仍然会丢失。

std::string是我们获得的最佳标准字符串,因此我不希望看到任何混乱。但我很少使用它;从我的角度来看,std::string有太多的缺点

答案 5 :(得分:2)

const std::string

你去吧。字符串文字也是不可变的,除非你想进入未定义的行为。

编辑:当然这只是故事的一半。 const字符串变量没有用,因为您无法使其引用新字符串。对const字符串的引用会这样做,除了C ++不允许像其他语言(如Python)一样重新分配引用。最接近的是指向动态分配字符串的智能指针。

答案 6 :(得分:1)

不可变的字符串非常好如果,只要有必要创建一个新字符串,内存管理器将始终能够确定每个字符串引用的位置。在大多数平台上,可以以相对适中的成本提供对这种能力的语言支持,但是在没有内置语言支持的平台上更加困难。

例如,如果想要在x86上设计支持不可变字符串的Pascal实现,则字符串分配器必须能够遍历堆栈以查找所有字符串引用;唯一的执行时间成本是需要一致的函数调用方法[例如不使用尾调用,并且每个非叶函数都保持一个帧指针]。分配有new的每个内存区域需要有一个位来指示它是否包含任何字符串,而那些包含字符串的内存需要有一个内存布局描述符的索引,但这些成本会非常小。

如果GC没有表来遍历堆栈,那么代码必须使用句柄而不是指针,并且当局部变量进入范围时让代码创建字符串句柄,并在它们被破坏时删除句柄超出范围。更大的开销。

答案 7 :(得分:0)

Qt还使用带有copy-on-write的不可变字符串 关于通过合适的编译器真正为您带来多少性能,存在一些争论。

答案 8 :(得分:0)

常量字符串对于值语义没有多大意义,并且共享不是C ++最大的优势之一......

答案 9 :(得分:-1)

Ruby中的字符串是可变的。

$ irb
>> foo="hello"
=> "hello"
>> bar=foo
=> "hello"
>> foo << "world"
=> "helloworld"
>> print bar
helloworld=> nil
  
      
  • 简单线程安全
  •   

我倾向于忘记安全论点。如果您想要是线程安全的,请将其锁定,或者不要触摸它。 C ++不是一种方便的语言,有自己的约定。

  
      
  • 更安全
  •   

没有。只要你有指针算术和不受保护的地址空间访问,就忘了保持安全。更安全的是编码无辜,是的。

  
      
  • 在大多数用例中,内存效率更高。
  •   

除非你实现了CPU密集型机制,否则我看不到。

  
      
  • 便宜的子串(标记化和切片)
  •   

这将是一个非常好的观点。可以通过引用带有反向引用的字符串来完成,其中对字符串的修改会导致副本。令牌化和切片变得免费,突变变得昂贵。

答案 10 :(得分:-4)

C ++字符串是线程安全的,所有不可变对象都保证是线程安全的,但Java的StringBuffer是可变的,就像C ++字符串一样,并且它们都是线程安全的。为什么要担心速度,使用const关键字定义方法或函数参数,告诉编译器字符串在该范围内是不可变的。此外,如果字符串对象是按需不可变的,等待你绝对需要使用字符串时,换句话说,当你将其他字符串附加到主字符串时,你有一个字符串列表,直到你真正需要整个字符串然后它们被连接在那一点。

不可变和可变对象以我所知的相同速度运行,除了它们的方法是利弊。常量基元和变量基元以不同的速度移动,因为在机器级别,变量被分配给需要一些二进制操作的寄存器或存储器空间,而常量是不需要任何这些的标签,因此更快(或者减少工作量)。仅适用于基元而不适用于对象。