代码之家  ›  专栏  ›  技术社区  ›  Aaron Daniels

字符串不变性

  •  12
  • Aaron Daniels  · 技术社区  · 16 年前

    字符串不可变是按语句工作的,还是按语句中的字符串工作的?

    例如,我了解以下代码将在堆上分配两个字符串。

    string s = "hello ";
    s += "world!";
    

    “hello”将一直保留在堆中,直到垃圾被收集;而s现在引用“hello world!”在堆里。但是,下面的行在堆上分配了多少字符串…1或2?此外,是否有工具/方法来验证结果?

    string s = "goodbye " + "cruel world!";
    
    9 回复  |  直到 7 年前
        1
  •  21
  •   Marc Gravell    16 年前

    编译器对字符串连接有特殊的处理,这就是为什么第二个示例只有 字符串。而“interning”意味着即使你运行这行20000次,仍然只有一个字符串。

    正在重新测试结果…最简单的方法(在本例中)可能是查看反射镜:

    .method private hidebysig static void Main() cil managed
    {
        .entrypoint
        .maxstack 1
        .locals init (
            [0] string s)
        L_0000: ldstr "goodbye cruel world!"
        L_0005: stloc.0 
        L_0006: ldloc.0 
        L_0007: call void [mscorlib]System.Console::WriteLine(string)
        L_000c: ret 
    }
    

    如你所见( ldstr )编译器已经为您完成了这项工作。

        2
  •  3
  •   Community CDub    8 年前

    文字字符串是 interned 这意味着 "hello " 位于堆中,但位于数据段中 [见评论] 对于program(因此不符合垃圾收集条件),同样适用于 "world" 至于 "hello world" 如果编译器足够聪明的话,这也可以作为实习生。

    "goodbye cruel world" 因为字符串文字串联是编译器处理的东西,所以需要进行内部处理。


    编辑: 我不确定数据段语句,请参阅 this question 更多信息。

        3
  •  0
  •   Charlie Martin    16 年前

    实际上,可能是3。一个常量字符串表示“再见”,一个常量字符串表示“残酷世界”,然后一个新字符串表示结果。

    您可以通过查看生成的代码来确定这一点。它取决于编译器(实际上,还取决于语言,这并不明显),但是您可以通过使用-a标志(我认为,检查手册页)来读取g++的输出来获取中间代码。

        4
  •  0
  •   Bill K    16 年前

    不要相信你对弦的“了解”。您可以查看字符串实现的源代码。例如,您的示例:

    string s = "goodbye " + "cruel world!";
    

    在Java中,将分配一个字符串。JAVA玩一些可爱的把戏,很难胜过——直到你需要的时候才优化!

    但据我所知,目前使用的是:

    String s="";
    for(int i=0;i<1000;i++)
        s+=" ";
    

    创建1000个空间字符串的效率仍然非常低

    在循环中追加是相当糟糕的,但否则它可能和StringBuilder一样高效。

        5
  •  0
  •   Joel Coehoorn    16 年前

    在这里要小心,因为当字符串值在编译时已知时,编译器可以进行一些非常不同的优化。如果直到运行时(从配置文件、数据库或用户输入中提取)才知道您使用的字符串,您将看到一些非常不同的IL。

        6
  •  0
  •   Stephane Grenier    16 年前

    如果你只需要做一两个字符串连接,我就不用担心了。

    但是,如果您有很多连接,或者您有一个循环,那么您肯定希望采取预防措施。在Java世界中,这意味着使用StringBuffer连接字符串。

        7
  •  0
  •   SeaDrive    16 年前

    如果不只是在一行中,则可以通过将第一个字符串放入StringBuffer、进行连接并返回结果字符串来完成两个字符串的连接。

    你自己创建StringBuffer可能看起来有点过分,但无论如何都会发生这种情况。-

        8
  •  0
  •   Richard Szalay    16 年前

    无论如何,不要过早地优化,但不要低估字符串连接的性能有多差。这不是对象创建,而是它导致的GC工作。

    上有一个实验室(ASP.NET升级工程师) Tess Ferrnandez's 博客是一个(相当极端的,理所当然的)例子 how string concatonation can bring a server to its knees .

        9
  •  -1
  •   Burkhard    16 年前

    如果编译器是“智能的”,它只会是一个带有“再见,残酷的世界”的字符串。