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

Shuffy

不斷的學(xué)習(xí),不斷的思考,才能不斷的進步.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條:
   
盡量使用“引用常量”傳參,而不是傳值

默認(rèn)情況下, 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ù)(傳值方式),它將返回這一學(xué)生的身份是否合法:

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

 

Student plato;                  // 柏拉圖是蘇格拉底的學(xué)生

 

 

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 對象,所以每當(dāng)你構(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 對象有可能會被修改。

通過引用傳參也可以避免“截斷問題”。當(dāng)一個派生類的對象以一個基類對象的形式傳遞(傳值方式)時,基類的拷貝構(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ù)來打印出當(dāng)前窗口的名字然后顯示這一窗口。下面是錯誤的實現(xiàn)方法:

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

{

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

 w.display();

}

考慮一下當(dāng)你將一個 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 ,而永遠(yuǎn)不會是 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ù)類型,當(dāng)你在傳值和傳遞常量引用之間徘徊時,傳值方式不失為一個更好的選擇。迭代器 STL 中的函數(shù)對象都是如此,這是因為它們設(shè)計的初衷就是更適于傳值,這是 C++ 的慣例。實現(xiàn)迭代器和函數(shù)對象的人員有責(zé)任考慮復(fù)制時的效率問題和截斷問題。(這就是一個“使用哪種規(guī)則,取決于當(dāng)前使用哪一部份的 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 值的對象放入寄存器時,編譯器就會報錯了。當(dāng)你遇到這種事情時,你可以使用引用傳遞這類對象,因為編譯器此時一定會將指針(引用的具體實現(xiàn))放入寄存器中。

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

總體上講,只有內(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>
            欧美成人激情视频| 欧美日韩伦理在线免费| 久久久久久久久久久久久久一区 | 欧美三级乱人伦电影| 欧美一级专区| 久久久久久久性| 老司机精品视频网站| 校园春色综合网| 欧美一区2区三区4区公司二百 | 国产精品青草综合久久久久99| 欧美日韩国产a| 国产精品永久免费观看| 国产一区二区三区在线观看精品 | 午夜欧美电影在线观看| 欧美在线观看视频一区二区| 久久久www成人免费无遮挡大片| 欧美在线视频导航| 欧美激情久久久| 亚洲性视频网址| 久久激情综合网| 欧美超级免费视 在线| 欧美精品系列| 国产免费一区二区三区香蕉精| 国产一区91精品张津瑜| 91久久黄色| 羞羞漫画18久久大片| 久久精品视频在线| 欧美激情按摩在线| 亚洲在线一区| 国产精品你懂得| 伊甸园精品99久久久久久| 亚洲精品资源| 久久综合伊人77777| 亚洲肉体裸体xxxx137| 亚洲香蕉网站| 亚洲第一页中文字幕| 亚洲线精品一区二区三区八戒| 久久精品亚洲精品| 国产精品高潮呻吟久久| 亚洲久久成人| 欧美一区二区私人影院日本| 亚洲国产综合视频在线观看| 最新国产成人av网站网址麻豆| 亚洲一区日韩在线| 91久久在线视频| 久久精品中文字幕免费mv| 欧美四级伦理在线| 99视频精品在线| 欧美国产日韩亚洲一区| 欧美一区国产二区| 国产精品毛片大码女人| 日韩午夜精品视频| 免费看av成人| 一区二区三区视频观看| 狼人社综合社区| 99re热这里只有精品免费视频| 欧美一区二视频| 国产精品手机在线| 午夜久久福利| 在线亚洲免费| 国产精品久久久久一区二区三区共| 亚洲精品综合精品自拍| 亚洲国产精品成人综合| 久久婷婷丁香| 亚洲国产高清aⅴ视频| 久久久久久久999精品视频| 欧美一区二区三区久久精品| 国产精品自在在线| 国产精品久在线观看| 亚洲一区欧美| 亚洲天堂激情| 欧美午夜精品久久久久久超碰| 国产精品99久久久久久www| 日韩一级免费| 欧美精品一线| 99亚洲精品| 日韩午夜电影| 亚洲国产另类久久精品| 亚洲国产精品久久久久秋霞蜜臀 | 欧美天天在线| 亚洲午夜久久久久久尤物| 亚洲精品乱码久久久久久日本蜜臀| 久久精品中文| 亚洲丁香婷深爱综合| 久久伊人一区二区| 男人的天堂亚洲| 亚洲愉拍自拍另类高清精品| 一区二区三区偷拍| 欧美日韩美女一区二区| 午夜亚洲伦理| 久久男人资源视频| 亚洲精品在线一区二区| 亚洲精选在线观看| 国产亚洲激情| 亚洲黄色有码视频| 国产精品乱子久久久久| 久久婷婷麻豆| 欧美日韩伦理在线| 久久尤物视频| 欧美国产成人在线| 久久精品国产免费观看| 欧美不卡视频| 久久久精品一区| 欧美不卡视频一区| 欧美一区二区三区四区在线观看地址| 久久国内精品自在自线400部| 亚洲全部视频| 午夜久久久久久| 日韩网站免费观看| 亚洲午夜久久久久久尤物| 国内久久精品| 亚洲高清视频一区二区| 日韩一级黄色av| 国产一区二区按摩在线观看| 欧美激情小视频| 国产女人aaa级久久久级| 亚洲精品国产精品久久清纯直播| 国产在线观看一区| 一区二区精品国产| 亚洲精品视频免费在线观看| 欧美综合国产| 欧美一区二区三区日韩视频| 欧美精品成人91久久久久久久| 欧美一区二区高清| 欧美电影免费观看| 蜜桃久久av一区| 国产精品v一区二区三区| 欧美激情第4页| 韩国av一区二区三区在线观看 | 亚洲免费成人| 久久精品视频99| 欧美一区二区| 欧美日韩伊人| 亚洲精品一二三| 日韩午夜精品视频| 欧美精品网站| 一区二区三区精品| 亚洲视频在线看| 欧美日韩亚洲一区二区三区在线观看| 欧美激情一区二区久久久| 在线欧美不卡| 老鸭窝亚洲一区二区三区| 欧美成人精品一区二区| 亚洲国产成人精品久久| 可以免费看不卡的av网站| 欧美国产欧美亚洲国产日韩mv天天看完整 | 亚洲欧美一区二区在线观看| 亚洲色图在线视频| 欧美三级视频| 亚洲综合日韩| 久久亚洲综合色| 亚洲国产精品电影| 欧美激情成人在线| 99视频在线精品国自产拍免费观看| 一区二区三区国产精华| 国产精品福利网站| 欧美一区二区三区免费观看| 免费短视频成人日韩| 亚洲国产国产亚洲一二三| 欧美电影电视剧在线观看| 亚洲免费精品| 久久精品99国产精品日本 | 国产精品天美传媒入口| 欧美中文字幕精品| 欧美激情一区在线观看| 亚洲视频成人| 国产在线精品二区| 美女脱光内衣内裤视频久久网站| 亚洲欧洲日夜超级视频| 欧美在线精品一区| 亚洲激情网址| 国产精品日韩在线观看| 麻豆国产精品777777在线| 99re6热只有精品免费观看| 久久精品国产一区二区电影| 亚洲青色在线| 激情懂色av一区av二区av| 欧美日韩亚洲成人| 久久gogo国模啪啪人体图| 亚洲精品视频免费| 久久在线观看视频| 亚洲摸下面视频| 亚洲日本激情| 激情婷婷欧美| 国产精品视频精品| 欧美另类99xxxxx| 久久久久久久999精品视频| 中文一区在线| 日韩午夜剧场| 亚洲国产天堂久久国产91| 久久精品夜夜夜夜久久| 亚洲一级在线| 亚洲另类视频| 欲色影视综合吧| 国产精品麻豆成人av电影艾秋| 久久欧美中文字幕| 欧美一区二区三区免费观看| 亚洲欧美综合国产精品一区| 亚洲靠逼com| 最新国产乱人伦偷精品免费网站|