原文地址:http://www.cppblog.com/mildcat1982/archive/2010/07/14/120390.aspx
1、在dev c++ IDE下,输入下面代码,检测string的实现机制。
2 using namespace std;
3
4 int main()
5 {
6 string str1 = "hello";
7 string str2(str1);
8
9 printf( "str1 address:%p\n", str1.c_str());
10 printf( "str2 address:%p\n", str2.c_str());
11 printf( "\n" );
12
13 str1[0];
14 printf( "str1 address:%p\n", str1.c_str());
15 printf( "str2 address:%p\n", str2.c_str());
16 printf( "\n" );
17
18 string str3(str1);
19 printf( "str1 address:%p\n", str1.c_str());
20 printf( "str3 address:%p\n", str3.c_str());
21 printf( "\n" );
22
23 string str4(str2);
24 printf( "str2 address:%p\n", str2.c_str());
25 printf( "str4 address:%p\n", str4.c_str());
26 printf( "\n" );
27
28 system("PAUSE");
29 return EXIT_SUCCESS;
30}
2、输出结果为:
2 str1 address:0036101C
3 str2 address:0036101C
4
5 str1 address:0036103C
6 str2 address:0036101C
7
8 str1 address:0036103C
9 str3 address:0036105C
10
11 str2 address:0036101C
12 str4 address:0036101C
13*/
3、结果解析
3.1 见代码第9行和第10行,为什么str1和str2的地址一致?
因为string内部的实现机制为引用计数,string的拷贝构造函数并非真正的去进行字符串拷贝,只是将字符串的引用数加1。
str1.c_str()和str2.c_str()实际上指的还是同一个字符串,同一块内存。
3.2 见代码第14行和第15行,为什么经过str1[0]这个看似无关痛痒的一行代码后,str1和str2的地址不再一致了?
具体而言,是str1的地址变化了,str2的地址保持不变。str1[0]到底做了什么?
string重载了[],一个是non-const版本,一个是const版本
char& operator[](size_t idx);
const char& operator[](size_t idx)const;
在上面的代码中,调用的是non-const版本,由于这个函数版本身是无法得知代码上下文中调用自己是为了读还是为了写,也就是无法区分以下两种情况:
cout << str[0];//读
str[0] = 'w'; // 写
理论上而言,在读时不需要在string内部对原字符串拷贝一份,只有在写时才需要对原字符串拷贝,由于无法区分读和写,或者说区分读和写比较困难,
所以我想DEV C++在string的实现上,应该是不区分读和写上下文,统一认为是写操作。
这样就造成一旦调用operator[],肯定在该函数内部进行了字符串拷贝操作。
从这个角度理解,str1的地址发生了变化,也是在情理之中的事情啦。
3.3、见代码第19行和第20行,为什么str1拷贝给str3后,两者的地址不一致?
是的,这个比较令人费解,尤其是考虑到str1刚拷贝给str2后,str1与str2的地址却是一致?貌似这是相悖的。
其实不然,仔细看一下,不难发现,str1是在调用完operator[]后才变成这个样子的。
看来operator[]不仅是进行了字符串拷贝,还对str1对象做了其他手脚。究竟是什么呢?
让我们先暂时撇开这个问题,看一下以下代码:
2 char * p = & s1[ 0 ];
3 string s2(s1);
4 * p = ' T';