代码之家  ›  专栏  ›  技术社区  ›  deft_code

不可变字符串与std::string

  •  61
  • deft_code  · 技术社区  · 16 年前

    我最近一直在读关于不可变字符串的文章 Why can't strings be mutable in Java and .NET? Why .NET String is immutable? 还有一些关于为什么 D 选择不可变字符串。似乎有很多优点。

    • 普通螺纹安全
    • 更安全
    • 在大多数用例中,内存效率更高。
    • 便宜的子字符串(标记化和切片)

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

    C++会受益于不可变的字符串吗?

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


    更新:

    对不可变字符串有两种尝试 const_string fix_str . 这两者都没有在五年内更新。它们还用过吗?为什么康斯特绳子没能让它成为助推器?

    11 回复  |  直到 7 年前
        1
  •  23
  •   anon    16 年前

    作为一种意见:

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

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

        2
  •  44
  •   jamylak    13 年前

    我发现大多数人都不太明白 immutable_string 是。不仅仅是关于警察。真正的力量 不可变的_字符串 是性能(即使在单线程程序中)和内存使用情况。

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

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

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

    当然,我们不能只使用两个数据成员来实现不可变的_字符串。实际的实现可能需要一个引用计数(或动态加权)内存块。这样地

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

    在大多数情况下,内存和性能都比传统的字符串要好,尤其是当您知道自己在做什么时。

    当然C++可以从不可变的字符串中获益,有一个字符串是很好的。我查过了 boost::const_string 以及 fix_str 库比提到的。这应该是我所说的。

        3
  •  9
  •   Notinlist    11 年前

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

    在Java中,如果你有 Person 然后你把 String name 和他在一起的人 getName() 方法,您唯一的保护是不可变的模式。如果它不在那里,你就必须 clone() 您的字符串可以整夜不停地使用(与数据成员有关,这些数据成员不是典型的值对象,但仍然需要保护)。

    在C++中你有 const std::string& getName() const . 所以你可以写 SomeFunction(person.getName()) 在什么地方 void SomeFunction(const std::string& subject) .

    • 没有复制
    • 如果有人想复制,他可以自由复制。
    • 技术适用于所有数据类型,而不仅仅是字符串
        4
  •  3
  •   Cubbi    16 年前

    你肯定不是唯一一个这么想的人。事实上,有 const_string 由叶戈鲁希金所著的图书馆,似乎已经被包含进了Boost的思想中。这里有一个新的图书馆, fix_str 罗兰·皮宾格。我不确定在运行时进行全绳实习有多困难,但在必要时,大多数优势是可以实现的。

        5
  •  3
  •   Keith Pinson sumit vedi    13 年前

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

    当内存便宜时,不可变的字符串是很好的。当C++被开发时,这是不正确的,在C++的所有平台上都不是这样。(在更有限的平台上,OTHO似乎比C++更常见,所以参数很弱。)

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

    STD::字符串 是最好的 标准 我们得到了绳子,所以我不想看到有什么乱七八糟的。不过,我很少使用它; STD::字符串 缺点太多了 在我看来 .

        6
  •  2
  •   Mark Ransom    16 年前
    const std::string
    

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

    编辑: 当然,这只是故事的一半。常量字符串变量并不有用,因为您不能使它引用新的字符串。对const字符串的引用可以做到这一点,只是C++不允许您重新分配引用,如Python之类的其他语言。最接近的东西是指向动态分配字符串的智能指针。

        7
  •  1
  •   supercat    11 年前

    不变的弦很好 如果 每当需要创建一个新的字符串时,内存管理器总是能够确定每个字符串引用的位置。在大多数平台上,这种能力的语言支持可以以相对较低的成本提供,但在没有内置这种语言支持的平台上,则要困难得多。

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

    如果GC不是遍历堆栈的表,那么就需要让代码使用句柄而不是指针,并让代码在局部变量进入作用域时创建字符串句柄,在句柄超出作用域时销毁这些句柄。开销要大得多。

        8
  •  0
  •   Martin Beckett    16 年前

    Qt还使用了不可变字符串和copy-on-write。
    关于它能为您带来多少性能,有一些争论。

        9
  •  0
  •   fredoverflow    16 年前

    常量字符串与值语义无关,共享不是C++最大的优点之一。

        10
  •  -1
  •   Pierre Carrier    15 年前

    字符串在Ruby中是可变的。

    $ irb
    >> foo="hello"
    => "hello"
    >> bar=foo
    => "hello"
    >> foo << "world"
    => "helloworld"
    >> print bar
    helloworld=> nil
    
    • 普通螺纹安全

    我倾向于忘记安全论据。如果你想保证线的安全,锁上它,或者不要碰它。C++不是一种方便的语言,有你自己的习惯。

    • 更安全

    不。一旦你有了指针运算和对地址空间的无保护访问,就忘记了安全。是的,可以更安全地防止无害的错误编码。

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

    除非您实现CPU密集型机制,否则我看不到如何实现。

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

    那将是一个非常好的观点。可以通过引用带有backreference的字符串来完成,其中对字符串的修改将导致复制。标记化和切片变得免费,突变变得昂贵。

        11
  •  -4
  •   yomi    14 年前

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

    据我所知,不变的和可变的物体以相同的速度运行,只是它们的方法是有利弊的。常量原语和变量原语以不同的速度移动,因为在机器级别,变量被分配到需要一些二进制操作的寄存器或内存空间,而常量是不需要这些操作的标签,因此速度更快(或完成的工作更少)。仅适用于基本体,不适用于对象。