C++臨時(shí)對(duì)象的析構(gòu)?這不是很簡(jiǎn)單么?其實(shí)沒那么簡(jiǎn)單。 我們先看看如下程序吧:
- #include <iostream>
- #include <string>
- using namespace std;
-
- string test()
- {
- return "abc";
- }
-
- int main()
- {
- const char *p = test().c_str();
- cout << p << endl;
-
- return 0;
- }
你可能迫切地期待結(jié)果為:abc, 其實(shí)不然。 為了簡(jiǎn)便起見, 我們簡(jiǎn)化一下上述程序:
- #include <iostream>
- #include <string>
- using namespace std;
-
- int main()
- {
- const char *p = string("abc").c_str();
- cout << p << endl;
-
- return 0;
- }
注意, 結(jié)果不是abc. 為什么呢? 我先直接說吧:string("abc")是一個(gè)臨時(shí)對(duì)象, 在執(zhí)行完const char *p = string("abc").c_str();這個(gè)語句后, 臨時(shí)對(duì)象就析構(gòu)了, 也就是說p指向的區(qū)域中的值變了。 所以, 結(jié)果自然不是abc.
這就引出了如下問題: 臨時(shí)對(duì)象是何時(shí)析構(gòu)的呢? 我們先看一個(gè)程序:
- #include <iostream>
- #include <string>
- using namespace std;
-
- class A
- {
- public:
- A()
- {
- cout << "A constructor" << endl;
- }
-
- ~A()
- {
- cout << "A destructor" << endl;
- }
- };
-
- int main()
- {
- A(); // 臨時(shí)對(duì)象
-
- printf("end xxx\n");
- printf("end yyy\n");
-
- return 0;
- }
稍微懂一點(diǎn)C++的人會(huì)說, 結(jié)果是:
A constructor
end xxx
end yyy
A destructor
其實(shí), 上述結(jié)果是錯(cuò)誤的, 真正的結(jié)果是:
A constructor
A destructor
end xxx
end yyy
看來, 在執(zhí)行完第一個(gè)語句后, 臨時(shí)對(duì)象A()就析構(gòu)了, 我們來看看匯編, 驗(yàn)證一下吧:
我們看到, 臨時(shí)對(duì)象確實(shí)是在printf之前析構(gòu)的。
好, 我們接著看:
- #include <iostream>
- #include <string>
- using namespace std;
-
- class A
- {
- public:
- A()
- {
- cout << "A constructor" << endl;
- }
-
- ~A()
- {
- cout << "A destructor" << endl;
- }
- };
-
- int main()
- {
- A(), // 注意, 是逗號(hào)運(yùn)算符
- printf("end xxx\n");
- printf("end yyy\n");
-
- return 0;
- }
運(yùn)行結(jié)果為:
A constructor
end xxx
A destructor
end yyy
不要驚訝, 查看匯編代碼就知道, 臨時(shí)對(duì)象是在 printf("end xxx\n");后析構(gòu)的。
繼續(xù)看代碼:
- #include <iostream>
- #include <string>
- using namespace std;
-
- class A
- {
- public:
- A()
- {
- cout << "A constructor" << endl;
- }
-
- ~A()
- {
- cout << "A destructor" << endl;
- }
- };
-
- int main()
- {
- A(), // 注意, 是逗號(hào)運(yùn)算符
- printf("end xxx\n"), // 注意, 是逗號(hào)運(yùn)算符
- printf("end yyy\n");
-
- return 0;
- }
運(yùn)行結(jié)果為:
A constructor
end xxx
end yyy
A destructor
不要驚訝, 查看匯編代碼就知道, 臨時(shí)對(duì)象是在 printf("end xxx\n");后析構(gòu)的。
由此可見, 臨時(shí)對(duì)象是在遇到其后的第一個(gè)分號(hào)(語句結(jié)束處)析構(gòu)的。
好, 我們?cè)倏纯矗?/p>
- #include <iostream>
- #include <string>
- using namespace std;
-
- int main()
- {
- const char *p = string("abc").c_str(); // 臨時(shí)對(duì)象在執(zhí)行完該句后析構(gòu)了
- cout << p << endl; // 此時(shí)p指向垃圾值
-
- return 0;
- }
一切一目了然。
大家在使用臨時(shí)對(duì)象的時(shí)候要留個(gè)心眼, 尤其是使用string的c_str時(shí), 一旦出錯(cuò), 經(jīng)常排查半天, 最后才發(fā)現(xiàn)栽倒在此處。 鑒于容易出錯(cuò), 最后, 我們?cè)倏匆谎郯桑?/p>
- #include <iostream>
- #include <string>
- using namespace std;
-
- int main()
- {
- const char *p = (string("abc") + string("def")).c_str(); // 臨時(shí)對(duì)象在執(zhí)行完該句后析構(gòu)了
- cout << p << endl; // 此時(shí)p指向垃圾值
-
- return 0;
- }
OK, 本文先到此為止。
備注: 在上面的程序中, 我使用的編譯器是VC++6.0, 后來網(wǎng)友“時(shí)光”提醒我, g++的編譯器會(huì)有不同的表現(xiàn)。 在此, 感謝“時(shí)光”。 另外, 為了寫出高質(zhì)量的可移植代碼, 仍需要注意避免使用臨時(shí)string對(duì)象的c_str方法。
|