国产毛片a精品毛-国产毛片黄片-国产毛片久久国产-国产毛片久久精品-青娱乐极品在线-青娱乐精品

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上都驗證過了,我覺得是不是編譯器做了相應的優化啊(特別是針對內置基本類型)。
    有想法的兄弟望賜教,感激不盡!!
    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所占的那塊棧空間的內存依然保持原樣,只是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://m.qingdxww.cn/thread-61370-1-1.html     【打印本頁】

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

廠商推薦

  • Microchip視頻專區
  • 深度體驗Microchip自動輔助駕駛應用方案——2025巡展開啟報名!
  • Cortex-M4外設 —— TC&TCC結合事件系統&DMA優化任務培訓教程
  • 你仿真過嗎?使用免費的MPLAB Mindi模擬仿真器降低設計風險
  • 利用模擬開發工具生態系統進行安全電路設計
  • 貿澤電子(Mouser)專區
關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
快速回復 返回頂部 返回列表
主站蜘蛛池模板: 精品一区二区三区免费站 | 女老师免费观看 | 欧美视频一区二区三区四区 | 成人看片黄a在线观看 | 日韩毛片基地 | 黄h视频 | 亚洲精品一卡2卡3卡三卡四卡 | 国产日韩亚洲欧美 | 男人a天堂| 国产精品一区二区久久不卡 | 亚洲四区| 青青草国产精品免费 | 欧美抠逼视频 | 国产在线精品一区二区中文 | 日韩一级在线 | 精品国产福利第一区二区三区 | 四虎影院免费观看视频 | 日韩手机视频 | 色婷婷综合久久久久中文一区二区 | 色综合久久久高清综合久久久 | 欧美性xxxx | 国产成人香蕉久久久久 | 日本免费中文字幕 | 日日日干干干 | 一区二区视频网 | 国产综合精品久久亚洲 | 色综合久久一区二区三区 | 日本成人免费在线 | 欧美大片天天免费看视频 | 久久久亚洲精品蜜桃臀 | 黄页网址在线观看 | 精品专区 | 欧美日韩视频二区三区 | 日本成人一区二区三区 | 欧美人与动欧交视频 | 国产精品免费观看视频播放 | 麻豆天美果冻星空91制片厂 | 国产成人欧美一区二区三区vr | 中文字幕一区在线观看 | 久久久久四虎国产精品 | 国产成人啪一区二区 |