不可变的stringvs std :: string

我最近一直在阅读关于不可变string的知识, 在这里和这里以及为什么Dselect了不可变string的一些东西。 似乎有很多优点。

  • 平凡线程安全
  • 更安全
  • 在大多数使用情况下更有效率。
  • 便宜的子串(标记和切片)

更何况大多数新语言都有不可变的string,D2.0,Java,C#,Python等等。

C ++会从不可变的string中受益吗?

是否有可能实现一个不变的string类在c + +(或c + + 0x),将具有所有这些优势?


更新:

有两个尝试在不可变的stringconst_string和fix_str 。 在过去的五年中都没有更新。 他们甚至用过吗? 为什么没有const_string使它成为提升?

作为一个观点:

  • 是的,我非常喜欢C ++的不可变string库。
  • 不,我不喜欢std :: string是不可变的。

是否真的值得做(作为标准库function)? 我会说不。 const的使用给你本地不可变的string,系统编程语言的基本性质意味着你确实需要可变string。

我发现这个线程中的大多数人不明白immutable_string是什么。 这不仅是关于常量。 immutable_string的真正威力在于性能(即使在单线程中)和内存使用情况。

想象一下,如果所有的string都是不可变的,并且所有的string都被实现了

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

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

当然,我们不能只用两个数据成员来实现一个immutable_string。 真正的实现可能需要引用计数(或加权)内存块。 喜欢这个

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

在大多数情况下,记忆和performance都会比传统的string更好,特别是当你知道你在做什么。

当然C ++可以从不可变的string中受益,而且有一个很好。 我已经检查了boost::const_stringfix_str提到的fix_str。 那些应该是我正在谈论的。

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

在Java中,如果您有一个Person类,并且使用getName()方法返回该人员的String name ,则唯一的保护是不可变的模式。 如果它不在那里,你将不得不clone()你的string昼夜(因为你必须做的数据成员不是典型的价值对象,但仍然需要保护)。

在C ++中,你有const std::string& getName() const 。 所以你可以写SomeFunction(person.getName()) ,就像void SomeFunction(const std::string& subject)

  • 没有复制发生
  • 如果有人想复制,他可以自由地这样做
  • 技术适用于所有数据types,而不仅仅是string

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

当内存很便宜时,不可变的string是很好的 – 当C ++被开发时,这不是真的,在C ++所有的平台上都不是这样。 (在更有限的平台上,OTOH似乎比C ++更普遍,所以这个论点很弱。)

您可以使用C ++创build一个不可变的string类,并且可以使其与std::string基本兼容,但与具有专用优化和语言function的内置string类相比,您仍然会失去它。

std::string是我们得到的最好的标准string,所以我不想看到任何混乱。 尽pipe如此,我很less使用它。 std::string 从我的angular度来看有太多的缺点。

你当然不是唯一的那个人。 实际上,Maxim Yegorushkin有一个const_string库,这个库似乎是用包含在内的方式编写的。 这里有一个更新的图书馆,Roland Pibinger的fix_str。 我不确定在实时运行时全串实习会有多棘手,但大多数优点在必要时都是可以实现的。

 const std::string 

你走了 string文字也是不可变的,除非你想进入未定义的行为。

编辑:当然,这只是故事的一半。 常量stringvariables是没有用的,因为你不能使它引用一个新的string。 对一个conststring的引用可以做到这一点,除了C ++不允许你重新分配一个引用,像其他语言,如Python。 最接近的是一个指向dynamic分配string的智能指针。

不可变的string是很好的,只要有必要创build一个新的string,内存pipe理器将总是能够确定每个string引用的位置。 在大多数平台上,以相对较低的成本提供对这种能力的语言支持,但是在没有这种语言支持的平台上build立起来就困难得多。

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

如果一个GC不是table来遍历堆栈,那么就需要代码使用句柄而不是指针,并且在局部variables进入作用域时有代码创buildstring句柄,并且当它们超出作用域时就把它们销毁。 更大的开销。

Qt也使用copy-on-write的不可变string。
对于使用体面的编译器真正购买你的性能有多less争议。

常量string与价值语义毫无关系,共享不是C ++最大的优势之一。

string在Ruby中是可变的。

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

我会倾向于忘记安全论据。 如果您想要线程安全,请locking或不要触摸它。 C ++不是一个方便的语言,有你自己的约定。

  • 更安全

不,只要你有指针算术和不受保护的地址空间访问,忘记安全。 对付无辜的糟糕的编码,是的。

  • 在大多数使用情况下更有效率。

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

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

这将是一个很好的观点。 可以通过引用带有反向引用的string来完成,其中对string的修改会导致副本。 令牌化和切片变得自由,变异变得昂贵。

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

不变的和可变的对象以我知道的速度运行,除了他们的方法是正反两方面的。 常量原语和variables原语以不同的速度移动,因为在机器级别,variables被分配给一个寄存器或一个需要less量二进制操作的内存空间,而常量是不需要任何这些variables的标签,因此速度更快更less的工作完成)。 只适用于基元而不适用于物体。