青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Shuffy

不斷的學習,不斷的思考,才能不斷的進步.Let's do better together!
posts - 102, comments - 43, trackbacks - 0, articles - 19

[轉(zhuǎn)]http://m.shnenglu.com/tiandejian/archive/2007/06/01/ec_20.html
第20條:
   
盡量使用“引用常量”傳參,而不是傳值

默認情況下, C++ 為函數(shù)傳入和傳出對象是采用傳值方式的(這是由 C 語言繼承而來的特征)。除非你明確使用其他方法,函數(shù)的形式參數(shù)總會通過復(fù)制實在參數(shù)的副本來創(chuàng)建,并且,函數(shù)的調(diào)用者得到的也是函數(shù)返回值得一個副本。這些副本是由對象的拷貝構(gòu)造函數(shù)創(chuàng)建的。這使得“傳值”成為一項代價十分昂貴的操作。請觀察下邊的示例中類的層次結(jié)構(gòu):

class Person {

public:

 Person();                      // 為簡化代碼省略參數(shù)表

 virtual ~Person();             // 7 條解釋了它為什么是虛函數(shù)

 ...

 

private:

 std::string name;

 std::string address;

};

 

class Student: public Person {

public:

 Student();                     // 再次省略參數(shù)表

 virtual ~Student();

 ...

 

private:

 std::string schoolName;

 std::string schoolAddress;

};

請觀察下面的代碼,這里我們調(diào)用一個名為 validateStudent 函數(shù),通過為這一函數(shù)傳進一個 Student 類型的參數(shù)(傳值方式),它將返回這一學生的身份是否合法:

bool validateStudent(Student s);// 通過傳值方式接受一個 Student 對象

 

Student plato;                  // 柏拉圖是蘇格拉底的學生

 

 

bool platoIsOK = (plato);   // 調(diào)用這一函數(shù)

在這個函數(shù)被調(diào)用時將會發(fā)生些什么呢?

很顯然地,在這一時刻,通過調(diào)用 Student 的拷貝構(gòu)造函數(shù),可以將這一函數(shù) s 參數(shù)初始化為 plato 的值 。同樣顯然的是, s validateStudent 返回的時候?qū)⒈讳N毀。所以這一函數(shù)中傳參的開銷就是調(diào)用一次 Student 的拷貝構(gòu)造函數(shù)和一次 Student 的析構(gòu)函數(shù)。

但是上邊的分析僅僅是冰山一角。一個 Student 對象包含兩個 string 對象,所以每當你構(gòu)造一個 Student 對象時,你都必須構(gòu)造兩個 string 對象。同時,由于 Student 類是從 Person 類繼承而來,所以在每次構(gòu)造 Student 對象時,你都必須再構(gòu)造一個 Person 對象。一個 Person 對象又包含兩個額外的 string 對象,所以每次對 Person 的構(gòu)造還要進行額外的兩次 string 的構(gòu)造。最后的結(jié)果是,通過傳值方式傳遞一個 Student 對象會引入以下幾個操作:調(diào)用一次 Student 的拷貝構(gòu)造函數(shù),調(diào)用一次 Person 的拷貝構(gòu)造函數(shù),調(diào)用四次 string 的拷貝構(gòu)造函數(shù)。在 Student 的這一副本被銷毀時,相應(yīng)的每次構(gòu)造函數(shù)調(diào)用都對應(yīng)著一次析構(gòu)函數(shù)的調(diào)用。因此我們看到:通過傳值方式傳遞一個 Student 對象總體的開銷究竟有多大?調(diào)用六次構(gòu)造函數(shù)和六次析構(gòu)函數(shù)!

下面向你介紹正確的方法,這一方法才會使函數(shù)擁有期望的行為。畢竟你期望的是所有對象以可靠的方式進行初始化和銷毀。然而,如果可以繞過所有這些構(gòu)造函數(shù)和析構(gòu)函數(shù)將是件很愜意的事情。那就是:通過引用常量傳遞參數(shù):

bool (const Student& s);

這樣做效率會提高很多:由于不會創(chuàng)建新的對象,所以就不會存在構(gòu)造函數(shù)或析構(gòu)函數(shù)的調(diào)用。改進的參數(shù)表中的 const 是十分重要的。由于早先版本的 validateStudent 通過傳值方式接收 Student 參數(shù),所以調(diào)用者了解:無論函數(shù)對于傳入的 Student 對象進行什么樣的操作,都不會對原對象造成任何影響, validateStudent 僅僅會對對象的副本進行修改。而改進版本中 Student 對象是以引用形式傳入的,有必要將其聲明為 const 的,因為如果不這樣,調(diào)用者就需要關(guān)心傳入 validateStudent Student 對象有可能會被修改。

通過引用傳參也可以避免“截斷問題”。當一個派生類的對象以一個基類對象的形式傳遞(傳值方式)時,基類的拷貝構(gòu)造函數(shù)就會被調(diào)用,此時,這一對象的獨有特征——使它區(qū)別于基類對象的特征會被“截掉”。剩下的只是一個簡單的基類對象,這并不奇怪,因為它是由基類構(gòu)造函數(shù)創(chuàng)建的。這肯定不是你想要的。請看下邊的示例,假設(shè)你正在使用一組類來實現(xiàn)一個圖形視窗系統(tǒng):

class Window {

public:

 ...

 std::string name() const;           // return name of window

 virtual void display() const;       // draw window and contents

};

 

class WindowWithScrollBars: public Window {

public:

 ...

 virtual void display() const;

};

所有的 Window 對象都有一個名字,可以通過 name 函數(shù)取得這個名字,所有的視窗可以被顯示出來,可以通過調(diào)用 display 實現(xiàn)。 display 是虛函數(shù),這一點告訴你簡單基類 Window 的對象與派生出的 WindowWithScrollBars 對象的顯示方式是不一樣的。(參見第 34 36 條)

現(xiàn)在,假設(shè)你期望編寫一個函數(shù)來打印出當前窗口的名字然后顯示這一窗口。下面是錯誤的實現(xiàn)方法:

void printNameAndDisplay(Window w)// 錯誤 ! 參數(shù)傳遞的對象將被截斷。

{

 std::cout << w.name();

 w.display();

}

考慮一下當你將一個 WindowWithScrollBars 對象傳入這個函數(shù)時將會發(fā)生些什么:

WindowWithScrollBars wwsb;

 

printNameAndDisplay(wwsb);

參數(shù) w 將被構(gòu)造——還記得么?它是通過傳值方式傳入的——就像一個 Window 對象,使 wwsb 具體化的獨有信息將被截掉。無論傳入函數(shù)的對象的具體類型是什么,在 printNameAndDisplay 的內(nèi)部, w 將總保有一個 Window 類的對象的身份(因為它本身就是一個 Window 的對象)。特別地,在 printNameAndDisplay 內(nèi)部對 display 的調(diào)用總會 Window::display ,而永遠不會是 WindowWithScrollBars::display

解決截斷問題的方法是:通過引用常量傳參:

void printNameAndDisplay(const Window& w)

{                               // 工作正常,參數(shù)將不會被截斷。

 std::cout << w.name();

 w.display();

}

現(xiàn)在 w 的類型就是傳入視窗對象的精確類型。

揭開 C++ 編譯器的面紗,你將會發(fā)現(xiàn)引用通常情況下是以指針的形式實現(xiàn)的,所以通過引用傳遞通常意味著實際上是在傳遞一個指針。因此,如果傳遞一個內(nèi)建數(shù)據(jù)類型的對象(比如 int ),傳值會被傳遞引用更為高效。那么,對于內(nèi)建數(shù)據(jù)類型,當你在傳值和傳遞常量引用之間徘徊時,傳值方式不失為一個更好的選擇。迭代器 STL 中的函數(shù)對象都是如此,這是因為它們設(shè)計的初衷就是更適于傳值,這是 C++ 的慣例。實現(xiàn)迭代器和函數(shù)對象的人員有責任考慮復(fù)制時的效率問題和截斷問題。(這就是一個“使用哪種規(guī)則,取決于當前使用哪一部份的 C++ ”,參見第 1 條)

內(nèi)建數(shù)據(jù)類型體積較小,所以一些人得出這樣的結(jié)論:所有體積較小的類型都適合使用傳值,即使它們是用戶自定義的。這是一個不可靠的推理。僅僅通過一個對象體積小并不能判定調(diào)用它的拷貝構(gòu)造函數(shù)的代價就很低。許多對象——包括大多數(shù) STL 容器——其中僅僅包含一個指針和很少量的其它內(nèi)容,但是復(fù)制這樣的對象的同時,它所指向的所有內(nèi)容都需要復(fù)制。這將會是一件十分昂貴的事情。

即使體積較小的對象的拷貝構(gòu)造函數(shù)不會帶來昂貴的開銷,它也會引入性能問題。一些編譯器對內(nèi)建數(shù)據(jù)類型和用戶自定義數(shù)據(jù)類型是分別對待的,即使它們的原始表示方式完全相同。比如說一些編譯器很樂意將一個單純的 double 值放入寄存器中,這是語言的常規(guī),但將僅包含一個 double 值的對象放入寄存器時,編譯器就會報錯了。當你遇到這種事情時,你可以使用引用傳遞這類對象,因為編譯器此時一定會將指針(引用的具體實現(xiàn))放入寄存器中。

小型用戶自定義數(shù)據(jù)類型不適用于傳值方式還有一個理由,那就是:作為用戶自定義類型,它們的大小并不是固定的。現(xiàn)在很小的類型在未來的版本中可能會變得很大,這是因為它的內(nèi)部實現(xiàn)方式可能會改變。即使是你更改了 C++ 語言的具體實現(xiàn)都可能會影響到類型的大小。比如,在我編寫上面的示例的時候,一些對標準庫中 string 實現(xiàn)的大小竟然達到了另一些的七倍

總體上講,只有內(nèi)建數(shù)據(jù)類型、 STL 迭代器和函數(shù)對象類型適用于傳值方式。對于所有其它的類型,都應(yīng)該遵循本條款中的建議:使用引用常量傳參,而不是傳值。

牢記在心

盡量使用引用常量傳參,而不是傳值方式。因為傳引用更高效,而且可以避免“截斷問題”。

對于內(nèi)建數(shù)據(jù)類型、 STL 迭代和函數(shù)對象類型,這一規(guī)則就不適用了,對它們來說通常傳值方式更實用。

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲黄色精品| 亚洲在线播放电影| 久久一二三国产| 国内精品久久久久久久影视蜜臀| 性久久久久久久久久久久| 午夜激情久久久| 亚洲电影免费在线观看| 国产精品久久毛片a| 欧美日韩精品免费在线观看视频| 亚洲精品一区在线观看| 久久精品视频在线免费观看| 小处雏高清一区二区三区| 亚洲在线一区二区| 久久激情婷婷| 国产精品久久999| 国产一区二区三区免费在线观看 | 一色屋精品视频在线看| 亚洲品质自拍| 亚洲午夜女主播在线直播| 蜜桃av久久久亚洲精品| 亚洲欧美日韩视频二区| 欧美精品成人在线| 久久亚洲视频| 国外成人在线视频| 亚洲卡通欧美制服中文| 在线播放不卡| 老司机精品福利视频| 亚洲乱码久久| 国产欧美一区二区三区久久人妖 | 久久国产精品色婷婷| 欧美另类久久久品| 伊人夜夜躁av伊人久久| 亚洲女爱视频在线| 久久久久久久久久久成人| 中文国产一区| 亚洲精品国产无天堂网2021| 伊人成人开心激情综合网| 国产欧美一区二区白浆黑人| 欧美另类综合| 欧美精品乱人伦久久久久久| 久久综合久久综合久久综合| 久久国产精品免费一区| 欧美伊人精品成人久久综合97 | 欧美一区二区久久久| 亚洲精品乱码久久久久久蜜桃麻豆 | 宅男噜噜噜66国产日韩在线观看| 欧美电影电视剧在线观看| 久久久国产成人精品| 久久久成人网| 欧美激情第六页| 91久久亚洲| 日韩亚洲精品视频| 国产精品99久久久久久www| 亚洲私拍自拍| 欧美一区二视频| 久久久蜜桃精品| 欧美3dxxxxhd| 欧美午夜视频| 激情久久五月| 亚洲人成在线观看网站高清| 一区二区日韩伦理片| 黄色工厂这里只有精品| 亚洲精品激情| 性欧美8khd高清极品| 久久综合久久综合久久综合| 91久久久亚洲精品| 亚洲欧美日本伦理| 中日韩男男gay无套| 欧美一区二区播放| 蜜臀久久99精品久久久久久9| 欧美劲爆第一页| 国产欧美精品在线| 亚洲黄色在线| 欧美一二三区在线观看| 另类尿喷潮videofree| 亚洲欧洲一区二区三区| 亚洲男女自偷自拍图片另类| 亚洲欧美日韩一区在线观看| 美国成人直播| 国产亚洲一区精品| 亚洲精品视频中文字幕| 欧美中文在线观看| 亚洲精品视频一区| 久久久久久香蕉网| 国产精品久久午夜夜伦鲁鲁| 亚洲国产欧洲综合997久久| 午夜精品久久久久久久久| 欧美成人综合在线| 亚洲国产精品尤物yw在线观看| 亚洲欧美国产精品va在线观看 | 亚洲欧美日韩国产| 亚洲人体大胆视频| 亚洲国产美国国产综合一区二区| 中文日韩在线视频| 欧美在线视频二区| 日韩视频在线一区| 久久视频在线看| 国产精品视频xxxx| 中国女人久久久| 欧美高清视频在线 | 亚洲在线视频观看| 国产精品v日韩精品v欧美精品网站| 国产精品一区久久| 亚洲伊人久久综合| 日韩亚洲在线| 欧美精品午夜视频| 国产一区二区三区在线免费观看| 小黄鸭精品密入口导航| 99精品国产在热久久| 欧美国产日韩一区二区在线观看| 韩国av一区二区三区四区| 欧美一级播放| 亚洲综合色激情五月| 欧美性猛交视频| 中文久久精品| 欧美国产国产综合| 欧美成人xxx| 亚洲精品在线免费观看视频| 欧美激情小视频| 欧美成人激情视频| 亚洲经典一区| 欧美国产一区二区三区激情无套| 美女尤物久久精品| 日韩亚洲在线| 亚洲美女中出| 国产精品久久久| 久久精品91| 久久久久成人精品| 永久久久久久| 亚洲高清自拍| 欧美日韩1区2区| 午夜一区二区三区不卡视频| 亚洲免费大片| 国产精品性做久久久久久| 欧美在线视频免费| 久久频这里精品99香蕉| 亚洲精品在线视频| 亚洲黄色成人| 国产裸体写真av一区二区| 欧美在线999| 另类综合日韩欧美亚洲| 99精品视频免费| 亚洲第一区色| 国产精品国产亚洲精品看不卡15| 欧美一区=区| 久久人人爽人人爽爽久久| 亚洲人成人一区二区在线观看| 日韩午夜激情| 国外视频精品毛片| 鲁大师成人一区二区三区 | 亚洲国产婷婷综合在线精品| 日韩视频免费在线观看| 国产精品久久久久aaaa九色| 久久精品最新地址| 亚洲女同同性videoxma| 红桃视频亚洲| aa级大片欧美| 亚洲国产美国国产综合一区二区| 欧美国产精品| 国产日韩欧美中文在线播放| 欧美国产综合一区二区| 国产精品美女www爽爽爽视频| 久久综合久久88| 免费成人小视频| 久久男人av资源网站| 欧美国产一区二区在线观看| 久久久国产精品一区二区中文| 国产精品久久久久婷婷| 99精品久久久| 夜夜夜久久久| 欧美国产综合一区二区| 欧美激情成人在线| 一区二区在线看| 久久成人免费日本黄色| 久久九九国产精品怡红院| 欧美一区二区在线免费观看| 欧美日韩国产色视频| 亚洲精品久久| 亚洲人成人77777线观看| 欧美国产精品日韩| 亚洲精品一区二区三区在线观看| 一本色道久久| 国产精品九九| 亚洲综合精品自拍| 欧美主播一区二区三区| 国内精品美女av在线播放| 欧美一二三区在线观看| 久久久精品日韩欧美| 在线免费观看日本一区| 欧美精品123区| 亚洲影院在线| 麻豆精品网站| 亚洲激情成人| 欧美午夜久久| 久久国产欧美精品| 亚洲国产欧洲综合997久久| 中文日韩在线| 尤物99国产成人精品视频| 美女久久一区| 亚洲一区二区三区精品动漫|