国产精品免费无遮挡无码永久视频-国产高潮视频在线观看-精品久久国产字幕高潮-国产精品99精品无码视亚

C++中返回的引用

發(fā)布時間:2011-4-7 21:09    發(fā)布者:1640190015
大家都知道一個常識:“千萬不要返回局部對象或變量的引用和指針”。
     既然所有C++權(quán)威的書上都要求“一定不要返回局部對象或變量的引用和指針”,那為什么C++編譯器不從語法上直接禁掉這種用法,讓你編譯通不過(在技術(shù)上應(yīng)該不難實(shí)現(xiàn)的)。如果只是建議的話,那么“返回局部對象或變量的引用和指針”是否有用武之地呢?(從理論上來講,我認(rèn)為這種做法似乎總是錯誤的,原因大家都知道。)
    EX(1)
    #include
    using namespace std;
    class CComplex
    {
    public:
    CComplex():real(0),image(0){}
    CComplex(double real,double image):real(real),image(image){}
    CComplex& operator+(const CComplex& second)
    {
    CComplex temp(real+second.real,image+second.image);
    return temp;
    }
    void Print()
    {
    cout《"("《real《"+"《image《"i)"《endl;
    }
    private:
    double real;
    double image;
    };
    int main()
    {
    CComplex a(2,4);
    CComplex b(1.5,3.5);
    CComplex c=a+b;
    c.Print();
    return 0;
    }
    operator+返回的是臨時對象的引用,為什么能正確地工作???
    EX(2)
    #include
    #include
    using namespace std;
    string& f()
    {
    string s("hello");
    return s;
    }
    int main()
    {
    cout《f()《endl;
    return 0;
    }
    同樣是對象,為什么string對象就不行,就因?yàn)閟tring比較特殊???
    EX(3)
    #include
    #include
    using namespace std;
    double& f()
    {
    double d(5.55);
    return d;
    }
    int main()
    {
    cout《f()《endl;
    return 0;
    }
    為什么內(nèi)置類型(int,float等均可)返回局部變量的引用總可以正確地工作???
    這個問題似乎以前已經(jīng)有人討論過,但一直沒有定論。
    不要跟我說運(yùn)行正確是因?yàn)槲疫\(yùn)氣好,運(yùn)氣不好地話就輸出任意值;
    我運(yùn)行了N次,未見任何異常,也不要說運(yùn)行上千萬次才有可能出問題;
    我在GCC和VS2010上都驗(yàn)證過了,我覺得是不是編譯器做了相應(yīng)的優(yōu)化啊(特別是針對內(nèi)置基本類型)。
    有想法的兄弟望賜教,感激不盡!!
    int main()
    {
    CComplex a(2,4);
    CComplex b(1.5,3.5);
    CComplex c=a+b;
    c.Print();
    return 0;
    }
    operator+返回的是臨時對象的引用,為什么能正確地工作???
    答:main函數(shù)在執(zhí)行之后,a,b入棧,接著a+b調(diào)用了operator+,temp也入棧,operator+執(zhí)行完后,temp出棧并調(diào)用析構(gòu)函數(shù),由于出棧僅僅是移動了PC指針,而你又未寫析構(gòu)函數(shù)將CComplex清零,因此temp所占的那塊棧空間的內(nèi)存依然保持原樣,只是PC指針已經(jīng)不再指向它,而operator+返回的引用其實(shí)指向的是temp所占內(nèi)存,然后在調(diào)用CComplex的默認(rèn)拷貝構(gòu)造的函數(shù)的時候,由于拷貝構(gòu)造函數(shù)的輸入?yún)?shù)也是引用,因此也指向temp那塊內(nèi)存,對此快內(nèi)存也會按照CComplex類型來進(jìn)行訪問,最后c就得到了temp的內(nèi)容。這里即使是寫成CComplex& c=a+b;結(jié)果也是能輸出temp的內(nèi)容的。此時你若在此句話后面再加幾個函數(shù)調(diào)用,這些函數(shù)必須要有參數(shù)或內(nèi)部定義有變量,然后再c.Print(),你會發(fā)現(xiàn)結(jié)果完全變了。
    EX(2)
    #include
    #include
    using namespace std;
    string& f()
    {
    string s("hello");
    return s;
    }
    int main()
    {
    cout《f()《endl;
    return 0;
    }
    同樣是對象,為什么string對象就不行,就因?yàn)閟tring比較特殊???
    答:因?yàn)閟在出棧的時候其析構(gòu)函數(shù)會將內(nèi)存都清掉,在外面還想訪問自然訪問不成功了。
    EX(3)
    #include
    #include
    using namespace std;
    double& f()
    {
    double d(5.55);
    return d;
    }
    int main()
    {
    cout《f()《endl;
    return 0;
    }
    答:理解了上面兩個答案,這個我就不用多說了吧。
    每個人必有其背后的深刻原因,只是受限于種種因素,人們不可能都去搞明白。更多時候,并不是原因不充分,只是人們以其自己的知識背景還不足以理解。
    一、為什么不禁用的問題
    為什么不禁引用返回局部變量,技術(shù)上真的是不難嗎?且,有足夠的必要嗎?請見以下例子:
    int *f1(int &ri)
    {
    return &ri;
    }
    int *f2()
    {
    int i=4;
    int *j;
    j=f1(i);
    return j;
    }
    int main()
    {
    int *p=f2();
    *p=6;
    return 0;
    }
    p在初始化后,*p生命期是否已經(jīng)結(jié)束了呢?我相信,如果這件事也得由編譯器去判斷,那么顯然,程序員全部可以下崗了,編譯器實(shí)在是太智能了,人還有必要存在嗎?但現(xiàn)有技術(shù)真的能嗎?如果能的話,要花多大開銷,這個開銷有必要嗎?“千萬不要返回局部對象或變量的引用和指針”應(yīng)該是個原則性的東西,它是個典型代表,其實(shí)大原則是“不要在自動變量(不管是表達(dá)式中間結(jié)果的臨時變量(如果它不能保證總優(yōu)化到寄存器中)還是源程序中有明確名字的auto變量)生命期結(jié)束后還試圖解引用它”。
    程序設(shè)計語言課一般會說語言的可寫性與可讀性是對矛盾,C語言的可寫性特別強(qiáng),既會給比較強(qiáng)的人非常靈活的選擇,又會讓入門者走不少彎路或者半途而廢。利器不是誰都能用得好,這與水平不水平?jīng)]什么關(guān)系,說人的水平不足夠使用C++,當(dāng)然也可以站在沒有學(xué)會用C++的人的立場,說C++太過于復(fù)雜,以至大多數(shù)人是學(xué)不會用不好的,但它的每個設(shè)計的確都有它的現(xiàn)實(shí)考慮,編程語言是很實(shí)在的東西,往往外貌冷冰冰但其為什么是這樣有充足原因。
    二、你的好運(yùn)氣
    你要是明白函數(shù)調(diào)用時局部變量是如何入棧出棧的,看看反匯編的代碼,并跟蹤一下堆棧的變化情況,你會設(shè)計出一個讓值產(chǎn)生變化的例子。如果這類錯誤后,導(dǎo)致被改變的值,并不是指針的值,則在這么小的程序中,系統(tǒng)不一定都崩潰,它不過是讓部分你沒照顧到的地方變了變值,卻沒有影響輸出。
    建議樓主閱讀一下TCPL有關(guān)臨時變量一節(jié),看看各種條件下生成的臨時變量的作用域,與給出名字的局部變量間,有何差同。
    三、其他一些為什么的例子
    關(guān)于C++的為什么特別多,如果你不是經(jīng)驗(yàn)豐富且善于思考,是很難理解為什么有這么多為什么的。當(dāng)然,為什么的多少,是個程度問題,有差異存在的地方就有程度問題,不同的人善用不同的東西,C++是“小眾”的,但還不至于只是幾個人的,畢竟TIOBE還排第3。
    1.operator重載的解析順序?yàn)槭裁慈绗F(xiàn)在標(biāo)準(zhǔn)那樣設(shè)計?是權(quán)衡了使用者的方便,和編譯器的效率之間的一種平衡,它過度自由帶來的是呈指數(shù)級上升的編譯時開銷,且該開銷并不一定值得。
    2.內(nèi)置數(shù)組,為什么不設(shè)置下標(biāo)檢測?如果檢測下標(biāo),定然就會在每次訪問下標(biāo)時,做是否越界的檢驗(yàn),這就帶來了運(yùn)行時開銷。如果你的算法非常好,定然不需要檢測下標(biāo),則語言假定一定要在每次訪問下標(biāo)時都判斷,就會影響效率并失去選擇的機(jī)會。如果設(shè)置N個選項,可以用來關(guān)閉或打開是否檢測下標(biāo),那不應(yīng)該是一種語言應(yīng)該干的,各有各的側(cè)重點(diǎn)。
    3.C語言傳數(shù)組參數(shù)為什么默認(rèn)是轉(zhuǎn)換成指針類型?以C語言產(chǎn)生那個年代的硬件條件,復(fù)制數(shù)組很奢侈,尤其函數(shù)被調(diào)用往往很頻繁,算法要盡量往不復(fù)制的情況下設(shè)計,如果實(shí)在必要,非要復(fù)制,你也可以手動memcpy嘛!總之它不是默認(rèn)項。C++給了用戶另一種選項,即通過加上引用,而使得能夠真正傳整個數(shù)組,不過這都是很多年以后的事了。
    4.for語句為什么有的靈活有的嚴(yán)格?像在Ada中的語法,便是禁止循環(huán)變量被改變,且不能設(shè)置步長值,要想達(dá)到這兩個目的,便只能用其他變量再過渡,這樣做是為了高度的安全。反之,C語言的for則非常靈活,也沒有Ada那么多的限制,但這種靈活并不能保證用戶用其寫出錯誤邏輯的代碼;VB的自由度則介于二者之間。不能因?yàn)檫@些語言的設(shè)計不同,而指責(zé)其中某一種語言為何不對某一語法特性做必要的限制,它真的必要嗎?個案好說,但綜合全局,很難評估。
    四、設(shè)計者們不傻
    且任何有影響力的技術(shù),其規(guī)范,都是經(jīng)過全球大量從業(yè)者多年實(shí)踐后,總結(jié)整理并論證出來的,并不是一個或幾個人拍拍腦袋就草率決定的,因此C++的新標(biāo)準(zhǔn)化過程要?dú)v時8年之久。Bjarne Stroustrup不傻,Herb Sutter, Stanley Lippman, Scott Meyer, Alexander Stepanov, Andrew Koenig等人也不傻,標(biāo)準(zhǔn)委員會都不是白給的,大多數(shù)細(xì)節(jié)問題早就被提出過。具體實(shí)現(xiàn),要難得多,這點(diǎn)語法層面上的皮毛問題,都不值一提。
本文地址:http://m.4huy16.com/thread-61370-1-1.html     【打印本頁】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點(diǎn)和對其真實(shí)性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問題,我們將根據(jù)著作權(quán)人的要求,第一時間更正或刪除。
sw9518 發(fā)表于 2011-4-21 09:22:45
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

廠商推薦

  • Microchip視頻專區(qū)
  • Microchip第22屆中國技術(shù)精英年會——采訪篇
  • 常見深度學(xué)習(xí)模型介紹及應(yīng)用培訓(xùn)教程
  • 電動兩輪車設(shè)計生態(tài)系統(tǒng)
  • Microchip第22屆中國技術(shù)精英年會上海首站開幕
  • 貿(mào)澤電子(Mouser)專區(qū)
關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表