副标题#e#
在编写应用措施时,我们常常要利用到字符串。C++尺度库中的<string>和<sstream>为我们 操纵字符串提供了许多的利便,譬喻:工具封装、安详和自动的范例转换、直接拼接、不必担忧越界等等。但 本日我们并不想长篇累牍得去先容这几个尺度库提供的成果,而是分享一下stringstream.str()的一个有趣的 现象。我们先来看一个例子:
1 #include <string>
2 #include <sstream>
3 #include <iostream>
4
5 using namespace std;
6
7 int main()
8 {
9 stringstream ss("012345678901234567890123456789012345678901234567890123456789");
10 stringstream t_ss("abcdefghijklmnopqrstuvwxyz");
11 string str1(ss.str());
12
13 const char* cstr1 = str1.c_str();
14 const char* cstr2 = ss.str().c_str();
15 const char* cstr3 = ss.str().c_str();
16 const char* cstr4 = ss.str().c_str();
17 const char* t_cstr = t_ss.str().c_str();
18
19 cout << "------ The results ----------" << endl
20 << "cstr1:\t" << cstr1 << endl
21 << "cstr2:\t" << cstr2 << endl
22 << "cstr3:\t" << cstr3 << endl
23 << "cstr4:\t" << cstr4 << endl
24 << "t_cstr:\t" << t_cstr << endl
25 << "-----------------------------" << endl;
26
27 return 0;
28 }
#p#副标题#e#
在看这段代码的输出功效之前,先问各人一个问题,这里cstr1、cstr2、cstr3和cstr4 打印出来功效是一 样的么?(相信读者心里会想:功效必定纷歧样的嘛,不然不消在这里“故弄玄虚”了。哈哈)
接下来,我 们来看一下这段代码的输出功效:
—— The results ———-
cstr1: 012345678901234567890123456789012345678901234567890123456789
cstr2: 012345678901234567890123456789012345678901234567890123456789
cstr3: abcdefghijklmnopqrstuvwxyz
cstr4: abcdefghijklmnopqrstuvwxyz
t_cstr: abcdefghijklmnopqrstuvwxyz
—————————–
这里,我们诧异地发明cstr3和cstr4竟 然不是ss所暗示的数字字符串,而是t_ss所暗示的字母字符串,这也太诡异了吧,但我们相信“真相只有一个 ”。下面我们通过再加几行代码来看看,为什么会呈现这个“诡异”的现象。
1 #include <string>
2 #include <sstream>
3 #include <iostream>
4
5 using namespace std;
6
7 #define PRINT_CSTR(no) printf("cstr" #no " addr:\t%p\n",cstr##no)
8 #define PRINT_T_CSTR(no) printf("t_cstr" #no " addr:\t%p\n",t_cstr##no)
9
10 int main()
11 {
12 stringstream ss ("012345678901234567890123456789012345678901234567890123456789");
13 stringstream t_ss("abcdefghijklmnopqrstuvwxyz");
14 string str1(ss.str());
15
16 const char* cstr1 = str1.c_str();
17 const char* cstr2 = ss.str().c_str();
18 const char* cstr3 = ss.str().c_str();
19 const char* cstr4 = ss.str().c_str();
20 const char* t_cstr = t_ss.str().c_str();
21
22 cout << "------ The results ----------" << endl
23 << "cstr1:\t" << cstr1 << endl
24 << "cstr2:\t" << cstr2 << endl
25 << "cstr3:\t" << cstr3 << endl
26 << "cstr4:\t" << cstr4 << endl
27 << "t_cstr:\t" << t_cstr << endl
28 << "-----------------------------" << endl;
29 printf("\n------ Char pointers ----------\n");
30 PRINT_CSTR(1);
31 PRINT_CSTR(2);
32 PRINT_CSTR(3);
33 PRINT_CSTR(4);
34 PRINT_T_CSTR();
35
36 return 0;
37 }
在上述代码中,我们把那几个字符串对应的地点打印出来,其输出功效为:
—— The results ———-
cstr1: 012345678901234567890123456789012345678901234567890123456789
cstr2: 012345678901234567890123456789012345678901234567890123456789
cstr3: abcdefghijklmnopqrstuvwxyz
cstr4: abcdefghijklmnopqrstuvwxyz
t_cstr: abcdefghijklmnopqrstuvwxyz
—————————–
—— Char pointers ——— –
cstr1 addr: 0x100200e4
cstr2 addr: 0x10020134
cstr3 addr: 0x10020014
cstr4 addr: 0x10020014
t_cstr addr: 0x10020014
从上面的输出,我们发明cstr3和cstr4字串符的地点跟t_cstr是一样,因此,cstr3、 cstr4和t_cstr的打印功效是一样的。凭据我们凡是的领略,当第17-19行挪用ss.str()时,将会发生三个 string工具,其对应的字符串也将会是差异的地点。
#p#分页标题#e#
而打印的功效汇报我们,真实环境不是这样的。其实 ,streamstring在挪用str()时,会返回姑且的string工具。而因为是姑且的工具,所以它在整个表达式竣事 后将会被析构。由于紧接着挪用的c_str()函数将获得的是这些姑且string工具对应的C string,而它们在这 个表达式竣事后是不被引用的,进而这块内存将被接纳而大概被此外内容所包围,因此我们将无法获得我们想 要的功效。固然有些环境下,这块内存并没有被此外内容所包围,于是我们仍然可以或许读到我们期望的字符串, (这点在这个例子中,可以通过将第20行删除来浮现)。但我们要强调的是,这种行为的正确性将是不被担保 的。
通过上述阐明,我们将代码修改如下:
1 #include <string>
2 #include <sstream>
3 #include <iostream>
4
5 using namespace std;
6
7 #define PRINT_CSTR(no) printf("cstr" #no " addr:\t%p\n",cstr##no)
8 #define PRINT_T_CSTR(no) printf("t_cstr" #no " addr:\t%p\n",t_cstr##no)
9
10 int main()
11 {
12 stringstream ss ("012345678901234567890123456789012345678901234567890123456789");
13 stringstream t_ss("abcdefghijklmnopqrstuvwxyz");
14 string str1(ss.str());
15
16 const char* cstr1 = str1.c_str();
17 const string& str2 = ss.str();
18 const char* cstr2 = str2.c_str();
19 const string& str3 = ss.str();
20 const char* cstr3 = str3.c_str();
21 const string& str4 = ss.str();
22 const char* cstr4 = str4.c_str();
23 const char* t_cstr = t_ss.str().c_str();
24
25 cout << "------ The results ----------" << endl
26 << "cstr1:\t" << cstr1 << endl
27 << "cstr2:\t" << cstr2 << endl
28 << "cstr3:\t" << cstr3 << endl
29 << "cstr4:\t" << cstr4 << endl
30 << "t_cstr:\t" << t_cstr << endl
31 << "-----------------------------" << endl;
32 printf("\n------ Char pointers ----------\n");
33 PRINT_CSTR(1);
34 PRINT_CSTR(2);
35 PRINT_CSTR(3);
36 PRINT_CSTR(4);
37 PRINT_T_CSTR();
38
39 return 0;
40 }
此刻我们将得到我们所期望的输出功效了:
—— The results ———-
cstr1: 012345678901234567890123456789012345678901234567890123456789
cstr2: 012345678901234567890123456789012345678901234567890123456789
cstr3: 012345678901234567890123456789012345678901234567890123456789
cstr4: 012345678901234567890123456789012345678901234567890123456789
t_cstr: abcdefghijklmnopqrstuvwxyz
—————————–
—— Char pointers ——— –
cstr1 addr: 0x100200e4
cstr2 addr: 0x10020134
cstr3 addr: 0x10020184
cstr4 addr: 0x100201d4
t_cstr addr: 0x10020014
此刻我们知道stringstream.str()要领将返回一个姑且的string工具,而它的生命周期 将在本表达式竣事后完结。当我们需要对这个string工具举办进一步操纵(譬喻得到对应的C string)时,我 们需要留意这个大概会导致非预期功效的“陷阱”。:)
最后,我们想强调一下:由于姑且工具占用 内存空间被从头利用的不确定性,这个陷阱不必然会明明袒暴露来。但不袒暴露来不代表行为的正确性,为了 制止“诡异”问题的产生,请只管回收能担保正确的写法。
别的,本文以上所有输出功效的运行情况是:
Red Hat Enterprise Linux Server release 5.8 (Tikanga)
Linux 2.6.18-308.el5 ppc64 GNU/Linux
gcc version 4.1.2 20080704 (Red Hat 4.1.2 -52)