在学习.net编程时,你一定有听到过这样的说法,System.String类是不可变字符串,也就是说你不能修改一个字符串的值。
比如以下这段代码
你并不是把s的值修改为world,而是生成了一个新的包含"world"的字符串,然后令s这个字符串的引用指向新的字符串,而原来的那个字符串就被抛弃掉了。
也正是基于String类的不可修改性,CLR采用了String Interning的技术来共享相同的字符串,以达到减少内存使用的目的。比如以下这段代码
s1和s2其实指向相同的字符串。
那么是不是我们真的没有办法改变一个string的值呢?当然不是,在C++/CLI中,我们可以使用一些特殊的手段来达到我们的目的!
比如以下这段代码
string s = "hello";
s = "world";
s = "world";
你并不是把s的值修改为world,而是生成了一个新的包含"world"的字符串,然后令s这个字符串的引用指向新的字符串,而原来的那个字符串就被抛弃掉了。
也正是基于String类的不可修改性,CLR采用了String Interning的技术来共享相同的字符串,以达到减少内存使用的目的。比如以下这段代码
string s1 = "hello";
string s2 = "hello";
if (Object.ReferenceEquals(s1, s2))
Console.WriteLine("They are same");
string s2 = "hello";
if (Object.ReferenceEquals(s1, s2))
Console.WriteLine("They are same");
s1和s2其实指向相同的字符串。
那么是不是我们真的没有办法改变一个string的值呢?当然不是,在C++/CLI中,我们可以使用一些特殊的手段来达到我们的目的!
String^ s1 = "hello";
String^ s2 = "hello";
interior_ptr<Char> p = const_cast<interior_ptr<Char> >(PtrToStringChars(s1));
for(; *p; *p++='a');
Console::WriteLine("{0} and {1}",s1,s2);
String^ s2 = "hello";
interior_ptr<Char> p = const_cast<interior_ptr<Char> >(PtrToStringChars(s1));
for(; *p; *p++='a');
Console::WriteLine("{0} and {1}",s1,s2);
PtrToStringChars(String^)是一个定义在vcclr.h头文件中的一个helper function,它返回一个类型为interior_ptr<const Char>的内部指针,指向String实例内部所包含的字符串,之所以返回类型是interior_ptr<const Char>而不是interior_ptr<Char>是因为不希望我们改变String实例内的字符串,不过既然我们执意要这么做,那么就让我们用一个const_cast<T>来把这个const搞掉!
运行以上代码你会发现,s2现在的内容已经是aaaaa,而不是hello了。
当然,以上例子只是说明存在修改string实例的内容的可能,并不是鼓励大家这么做。虽然直接访问string实例内部的字符串,可能会带来一些性能上的好处。但是由于String Interning的存在,修改String实例内部的字符串是相当危险的行为,比如上面的那个例子中,你会发现,s1的输出也变成aaaaa了!