條款31: 千萬不要返回局部對象的引用,也不要返回函數(shù)內(nèi)部用new初始化的指針的引用
2 #include<string>
3
4 using namespace std;
5
6 class SimpleCat
7 {
8 public:
9 SimpleCat(void);
10 SimpleCat(int age,int weight);
11 int GetAge(){return itsAge;}
12 int GetWeight(){return itsWeight;}
13
14 private:
15 int itsAge;
16 int itsWeight;
17 //int itsAge=5;//1>.\SimpleCat.cpp(14) : error C2864: “SimpleCat::itsAge”: 只有靜態(tài)常量整型數(shù)據(jù)成員才可以在類中初始化
18
19 public:
20 virtual ~SimpleCat(void);
21 };
22
23 SimpleCat::SimpleCat(void)
24 {
25 cout<<"SimpleCat constructor "<<this<<endl;
26 }
27
28 SimpleCat::SimpleCat(int age,int weight)
29 {
30 cout<<"SimpleCat constructor "<<this<<endl;
31 itsAge = age;
32 itsWeight = weight;
33 }
34
35 SimpleCat::~SimpleCat(void)
36 {
37 cout<<"SimpleCat destructor"<<this<<endl;
38 }
39
40 SimpleCat &TheFunction();
41
42 int main()
43 {
44 SimpleCat myCat;
45 cout<<myCat.GetAge()<<endl;//這個值區(qū)別于java不是賦初值為0的,而是一個隨機(jī)的值
46 // cout<<myCat.itsAge<<endl;
47
48 cout<<"------------------------"<<endl;
49 SimpleCat &rCat = TheFunction();
50 int age = rCat.GetAge();
51 cout<<"rCat is "<<age<<"yeas old!"<<endl;
52 cout<<"&rCat: "<<&rCat<<endl;
53 SimpleCat *pCat = &rCat;
54 //delete rCat;//不能對引用使用delete
55 delete pCat;
56 //delete好像沒有釋放內(nèi)存,怎么獲取的還是原來的值
57 //可能在這個內(nèi)存區(qū)域存放的還是原來的?先new string后再調(diào)用也沒變,與編譯器有關(guān)還是什么??
58 for(int i =0;i<10;i++)
59 {
60 //想通過創(chuàng)建string對象來填充之前的內(nèi)存區(qū)間,好像沒用
61 string *s = new string("abcdefghijklmn");
62 }
63
64 //這時問題來了,rCat.getAge()為123了
65 SimpleCat *pSecond = new SimpleCat(123,444);
66
67 cout<<"delete pCat后再使用rCat引用會發(fā)生什么問題???"<<endl;
68 cout<<"delete pCat后 &rCat"<<&rCat<<endl;
69 cout<<"delete pCat后 rCat.age"<<rCat.GetAge()<<endl;
70
71 cout<<"--------------------------"<<endl;
72 SimpleCat myCat2 = TheFunction();//這個會發(fā)生內(nèi)存泄漏,在函數(shù)中申請的內(nèi)存會得不到釋放
73 //myCat2是通過默認(rèn)的拷貝函數(shù)來進(jìn)行初始化的
74 cout<<"myCat2的地址是 "<<&myCat2<<endl;
75 return 0;
76 }
77
78
79 //這個函數(shù)在返回時,是否會創(chuàng)建一個臨時引用變量???
80 //TheFunctionTwo(SimpleCat &simpleCat)這個函數(shù)在傳遞參數(shù)時是否會創(chuàng)建一個臨時的引用變量
81 //臨時的引用變量的作用域范圍是什么
82 SimpleCat &TheFunction()
83 {
84 SimpleCat *pFrisky = new SimpleCat(5,9);
85 cout<<"pFrisky: "<<pFrisky<<endl;
86 return *pFrisky;
87 }
88
89
90
函數(shù)TheFunction()的返回值被賦值給對SimpleCat類的一個引用,然后使用這個引用來獲得對象的成員變量age的值
為了證明函數(shù)TheFunction()在自由存儲區(qū)中創(chuàng)建的對象被賦給了函數(shù)main()聲明的引用,對rCat采取取址運(yùn)算,很明顯,它顯示了其引用的對象的地址,并且和自由存儲區(qū)中的對象的地址相匹配。
這一切看上去都很正確,但是如何釋放被占用的內(nèi)存,對于引用是不能使用delete運(yùn)算符的,一個筆記聰明的方法是聲明另一個指針,并使用由rCat得到的地址對它進(jìn)行初始化。這樣做確實可以釋放內(nèi)存,避免了內(nèi)存的泄漏,但是存在一個小問題,在delete pCat后,rCat引用又代表什么呢??引用必須是一個實際對象的別名;如果引用一個空對象的話(現(xiàn)在就是這種情況)那么程序就是無效的。。
注意:不能過分去強(qiáng)調(diào)一個使用對空對象的引用的程序,也行能通過編譯,但是即使程序通過了編譯,它仍然是病態(tài)的,而且執(zhí)行結(jié)果也是不可預(yù)料的
關(guān)于這個問題,存在這3種解決方案
第1種是在第49行聲明一個SimpleCat類對象,然后從函數(shù)TheFunction()中采取值傳遞的方式返回它的局部對象,這時不能在自由存儲區(qū)來分配對象空間,不能使用new,
第2種是在函數(shù)TheFunction()中聲明一個位于自由存儲區(qū)中的SimpleCat類的對象,但是讓函數(shù)返回一個指向內(nèi)存區(qū)域的指針,然后完成對對象的操作,調(diào)用函數(shù)可以刪除這個指針
第3種可行的方案,也是正確的,是在調(diào)用函數(shù)中聲明對象,然后通過引用的方式把它傳遞給函數(shù)TheFunction()
也意味在main函數(shù)中不能這樣使用了