為什麼C++中千萬不要返回局部對象或變數的引用和指標

來源:互聯網
上載者:User

大家都知道一個常識:“C++中千萬不要返回局部對象或變數的引用和指標”。

既然所有C++權威的書上都要求“一定不要返回局部對象或變數的引用和指標”,那為什麼C++編譯器不從文法上直接禁掉這種用法。如果只是建議的話,那麼“返回局部對象或變數的引用和指標”是否有用武之地呢?(從理論上來講,我認為這種做法似乎總是錯誤的,原因大家都知道。)
例1:
class CComplex

{

public:

         CComplex():real(0),image(0){}

         CComplex(doublereal,double image):real(real),image(image){}

 

         CComplex& operator+(const CComplex& second)

         {

                   CComplextemp(real+second.real,image+second.image);

 

                   returntemp;

         }

 

         voidPrint()

         {

                   cout << "(" << real << "+" << image << "i)" << endl;

         }

 

private:

         doublereal;

         doubleimage;

};

 

int main()

{

         CComplex a(2,4);

         CComplex b(1.5,3.5);

 

         CComplex c=a+b;

         c.Print();

 

         return0;

}

 

  operator+返回的是臨時對象的引用,為什麼能正確地工作???

例2
string& f()

{

         string s("hello");

 

         returns;

}

 

int main()

{

         cout << f() << endl;

 

         return0;

}

  同樣是對象,為什麼string對象就不行,就因為string比較特殊???

例子3
double& f()

{

         doubled(5.55);

 

         returnd;

}

 

int main()

{

         cout << f() << endl;

 

         return0;

}

  為什麼內建類型(int,float等均可)返回局部變數的引用總可以正確地工作???

  operator+返回的是臨時對象的引用,為什麼能正確地工作???
  答:main函數在執行之後,a,b入棧,接著a+b調用了operator+,temp也入棧,operator+執行完後,temp出棧並調用解構函式,由於出棧僅僅是移動了PC指標,而你又未寫解構函式將CComplex清零,因此temp所佔的那塊棧空間的記憶體依然保持原樣,只是PC指標已經不再指向它,而operator+返回的引用其實指向的是temp所佔記憶體,然後在調用CComplex的預設拷貝構造的函數的時候,由於拷貝建構函式的輸入參數也是引用,因此也指向temp那塊記憶體,對此快記憶體也會按照CComplex類型來進行訪問,最後c就得到了temp的內容。這裡即使是寫成CComplex&
c=a+b;結果也是能輸出temp的內容的。此時你若在此句話後面再加幾個函數調用,這些函數必須要有參數或內部定義有變數,然後再c.Print(),你會發現結果完全變了。

  同樣是對象,為什麼string對象就不行,就因為string比較特殊???
  答:因為s在出棧的時候其解構函式會將記憶體都清掉,在外面還想訪問自然訪問不成功了。

  一、為什麼不禁用的問題
  為什麼不禁引用返回局部變數,技術上真的是不難嗎?且,有足夠的必要嗎?請見以下例子:

int *f1(int &ri)

{

         return&ri;

}

 

int *f2()

{

         inti=4;

         int *j;

 

         j=f1(i);

 

         returnj;

}

 

int main()

{

         int*p=f2();

 

         *p=6;

 

         return0;

}

  p在初始化後,*p生命期是否已經結束了呢?我相信,如果這件事也得由編譯器去判斷,那麼顯然,程式員全部可以下崗了,編譯器實在是太智能了,人還有必要存在嗎?但現有技術真的能嗎?如果能的話,要花多大開銷,這個開銷有必要嗎?“千萬不要返回局部對象或變數的引用和指標”應該是個原則性的東西,它是個典型代表,其實大原則是“不要在自動變數(不管是運算式中間結果的臨時變數(如果它不能保證總最佳化到寄存器中)還是來源程式中有明確名字的auto變數)生命期結束後還試圖解引用它”。

  程式設計語言課一般會說語言的可寫性與可讀性是對矛盾,C語言的可寫性特彆強,既會給比較強的人非常靈活的選擇,又會讓入門者走不少彎路或者半途而廢。利器不是誰都能用得好,這與水平不水平沒什麼關係,說人的水平不足夠使用C++,當然也可以站在沒有學會用C++的人的立場,說C++太過於複雜,以至大多數人是學不會用不好的,但它的每個設計的確都有它的現實考慮,程式設計語言是很實在的東西,往往外貌冷冰冰但其為什麼是這樣有充足原因。

  二、你的好運氣

  你要是明白函數調用時局部變數是如何入棧出棧的,看看反組譯碼的代碼,並跟蹤一下堆棧的變化情況,你會設計出一個讓值產生變化的例子。如果這類錯誤後,導致被改變的值,並不是指標的值,則在這麼小的程式中,系統不一定都崩潰,它不過是讓部分你沒照顧到的地方變了變值,卻沒有影響輸出。

  建議樓主閱讀一下TCPL有關臨時變數一節,看看各種條件下產生的臨時變數的範圍,與給出名字的局部變數間,有何差同。

  三、其他一些為什麼的例子

  關於C++的為什麼特別多,如果你不是經驗豐富且善于思考,是很難理解為什麼有這麼多為什麼的。當然,為什麼的多少,是個程度問題,有差異存在的地方就有程度問題,不同的人善用不同的東西,C++是“小眾”的,但還不至於只是幾個人的,畢竟TIOBE還排第3。

  1.operator重載的解析順序為什麼如現在標準那樣設計?是權衡了使用者的方便,和編譯器的效率之間的一種平衡,它過度自由帶來的是呈指數級上升的編譯時間開銷,且該開銷並不一定值得。

  2.內建數組,為什麼不設定下標檢測?如果檢測下標,定然就會在每次訪問下標時,做是否越界的檢驗,這就帶來了運行時開銷。如果你的演算法非常好,定然不需要檢測下標,則語言假定一定要在每次訪問下標時都判斷,就會影響效率並失去選擇的機會。如果設定N個選項,可以用來關閉或開啟是否檢測下標,那不應該是一種語言應該乾的,各有各的側重點。

  3.C語言傳數組參數為什麼預設是轉換成指標類型?以C語言產生那個年代的硬體條件,複製數組很奢侈,尤其函數被調用往往很頻繁,演算法要盡量往不複製的情況下設計,如果實在必要,非要複製,你也可以手動memcpy嘛!總之它不是預設項。C++給了使用者另一種選項,即通過加上引用,而使得能夠真正傳整個數組,不過這都是很多年以後的事了。

  4.for語句為什麼有的靈活有的嚴格?像在Ada中的文法,便是禁止迴圈變數被改變,且不能設定步長值,要想達到這兩個目的,便只能用其他變數再過渡,這樣做是為了高度的安全。反之,C語言的for則非常靈活,也沒有Ada那麼多的限制,但這種靈活並不能保證使用者用其寫出錯誤邏輯的代碼;VB的自由度則介於二者之間。不能因為這些語言的設計不同,而指責其中某一種語言為何不對某一文法特性做必要的限制,它真的必要嗎?個案好說,但綜合全域,很難評估。

  四、設計者們不傻

  且任何有影響力的技術,其規範,都是經過全球大量從業者多年實踐後,總結整理並論證出來的,並不是一個或幾個人拍拍腦袋就草率決定的,因此C++的新標準化過程要曆時8年之久。Bjarne Stroustrup不傻,Herb Sutter, Stanley Lippman, ScottMeyer, Alexander Stepanov, Andrew Koenig等人也不傻,標準委員會都不是白給的,大多數細節問題早就被提出過。具體實現,要難得多,這點文法層面上的皮毛問題,都不值一提。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.