<var id="fnfpo"><source id="fnfpo"></source></var>
<rp id="fnfpo"></rp>

<em id="fnfpo"><object id="fnfpo"><input id="fnfpo"></input></object></em>
<em id="fnfpo"><acronym id="fnfpo"></acronym></em>
  • <th id="fnfpo"><track id="fnfpo"></track></th>
  • <progress id="fnfpo"><track id="fnfpo"></track></progress>
  • <tbody id="fnfpo"><pre id="fnfpo"></pre></tbody>

  • x
    x

    C++中返回的引用

    發布時間:2011-4-7 21:09    發布者:1640190015
    大家都知道一個常識:“千萬不要返回局部對象或變量的引用和指針”。
         既然所有C++權威的書上都要求“一定不要返回局部對象或變量的引用和指針”,那為什么C++編譯器不從語法上直接禁掉這種用法,讓你編譯通不過(在技術上應該不難實現的)。如果只是建議的話,那么“返回局部對象或變量的引用和指針”是否有用武之地呢?(從理論上來講,我認為這種做法似乎總是錯誤的,原因大家都知道。)
        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對象就不行,就因為string比較特殊???
        EX(3)
        #include
        #include
        using namespace std;
        double& f()
        {
        double d(5.55);
        return d;
        }
        int main()
        {
        cout《f()《endl;
        return 0;
        }
        為什么內置類型(int,float等均可)返回局部變量的引用總可以正確地工作???
        這個問題似乎以前已經有人討論過,但一直沒有定論。
        不要跟我說運行正確是因為我運氣好,運氣不好地話就輸出任意值;
        我運行了N次,未見任何異常,也不要說運行上千萬次才有可能出問題;
        我在GCC和VS2010上都驗證過了,我覺得是不是編譯器做了相應的優化。ㄌ貏e是針對內置基本類型)。
        有想法的兄弟望賜教,感激不盡!
        int main()
        {
        CComplex a(2,4);
        CComplex b(1.5,3.5);
        CComplex c=a+b;
        c.Print();
        return 0;
        }
        operator+返回的是臨時對象的引用,為什么能正確地工作???
        答:main函數在執行之后,a,b入棧,接著a+b調用了operator+,temp也入棧,operator+執行完后,temp出棧并調用析構函數,由于出棧僅僅是移動了PC指針,而你又未寫析構函數將CComplex清零,因此temp所占的那塊?臻g的內存依然保持原樣,只是PC指針已經不再指向它,而operator+返回的引用其實指向的是temp所占內存,然后在調用CComplex的默認拷貝構造的函數的時候,由于拷貝構造函數的輸入參數也是引用,因此也指向temp那塊內存,對此快內存也會按照CComplex類型來進行訪問,最后c就得到了temp的內容。這里即使是寫成CComplex& c=a+b;結果也是能輸出temp的內容的。此時你若在此句話后面再加幾個函數調用,這些函數必須要有參數或內部定義有變量,然后再c.Print(),你會發現結果完全變了。
        EX(2)
        #include
        #include
        using namespace std;
        string& f()
        {
        string s("hello");
        return s;
        }
        int main()
        {
        cout《f()《endl;
        return 0;
        }
        同樣是對象,為什么string對象就不行,就因為string比較特殊???
        答:因為s在出棧的時候其析構函數會將內存都清掉,在外面還想訪問自然訪問不成功了。
        EX(3)
        #include
        #include
        using namespace std;
        double& f()
        {
        double d(5.55);
        return d;
        }
        int main()
        {
        cout《f()《endl;
        return 0;
        }
        答:理解了上面兩個答案,這個我就不用多說了吧。
        每個人必有其背后的深刻原因,只是受限于種種因素,人們不可能都去搞明白。更多時候,并不是原因不充分,只是人們以其自己的知識背景還不足以理解。
        一、為什么不禁用的問題
        為什么不禁引用返回局部變量,技術上真的是不難嗎?且,有足夠的必要嗎?請見以下例子:
        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生命期是否已經結束了呢?我相信,如果這件事也得由編譯器去判斷,那么顯然,程序員全部可以下崗了,編譯器實在是太智能了,人還有必要存在嗎?但現有技術真的能嗎?如果能的話,要花多大開銷,這個開銷有必要嗎?“千萬不要返回局部對象或變量的引用和指針”應該是個原則性的東西,它是個典型代表,其實大原則是“不要在自動變量(不管是表達式中間結果的臨時變量(如果它不能保證總優化到寄存器中)還是源程序中有明確名字的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, Scott Meyer, Alexander Stepanov, Andrew Koenig等人也不傻,標準委員會都不是白給的,大多數細節問題早就被提出過。具體實現,要難得多,這點語法層面上的皮毛問題,都不值一提。
    本文地址:http://www.portaltwn.com/thread-61370-1-1.html     【打印本頁】

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

    廠商推薦

    • Microchip視頻專區
    • EtherCAT®和Microchip LAN925x從站控制器介紹培訓教程
    • MPLAB®模擬設計器——在線電源解決方案,加速設計
    • 讓您的模擬設計靈感,化為觸手可及的現實
    • 深度體驗Microchip自動輔助駕駛應用方案——2025巡展開啟報名!
    • 貿澤電子(Mouser)專區
    關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
    電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
    快速回復 返回頂部 返回列表
    精品一区二区三区自拍图片区_国产成人亚洲精品_亚洲Va欧美va国产综合888_久久亚洲国产精品五月天婷