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

洛譯小筑

別來(lái)無(wú)恙,我的老友…
隨筆 - 45, 文章 - 0, 評(píng)論 - 172, 引用 - 0
數(shù)據(jù)加載中……

[ECPP讀書筆記 條目20] 傳參時(shí)要多用“引用常量”,少用傳值

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

class Person {

public:

  Person();                        // 省略參數(shù)表以簡(jiǎn)化代碼

  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;

};

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

bool validateStudent(Student s);         // 通過(guò)傳值方式接受一個(gè)Student對(duì)象

 

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

 

 

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

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

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

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

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

bool validateStudent(const Student& s);

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

通過(guò)引用傳參也可以避免“截?cái)鄦?wèn)題”。當(dāng)一個(gè)派生類的對(duì)象以一個(gè)基類對(duì)象的形式傳遞(傳值方式)時(shí),基類的拷貝構(gòu)造函數(shù)就會(huì)被調(diào)用,此時(shí),這一對(duì)象的獨(dú)有特征——使它區(qū)別于基類對(duì)象的特征會(huì)被“截掉”。剩下的只是一個(gè)簡(jiǎn)單的基類對(duì)象,這并不奇怪,因?yàn)樗怯苫悩?gòu)造函數(shù)創(chuàng)建的。這肯定不是你想要的。請(qǐng)看下邊的示例,假設(shè)你正在使用一組類來(lái)實(shí)現(xiàn)一個(gè)圖形窗口系統(tǒng):

class Window {

public:

  ...

  std::string name() const;        // 返回窗口的名字

  virtual void display() const;    // 繪制窗口和內(nèi)容

};

 

class WindowWithScrollBars: public Window {

public:

  ...

  virtual void display() const;

};

所有的Window對(duì)象都有一個(gè)名字,可以通過(guò)name函數(shù)取得。所有的窗口都可以被顯示出來(lái),可以通過(guò)調(diào)用display實(shí)現(xiàn)。display是虛函數(shù),這一事實(shí)告訴我們,簡(jiǎn)單基類Window的對(duì)象與派生出的WindowWithScrollBars對(duì)象的顯示方式是不一樣的。(參見條目3436

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

void printNameAndDisplay(Window w) // 錯(cuò)誤! 參數(shù)傳遞的對(duì)象將被截?cái)啵?/span>

{

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

  w.display();

}

考慮一下當(dāng)你將一個(gè)WindowWithScrollBars對(duì)象傳入這個(gè)函數(shù)時(shí)將會(huì)發(fā)生些什么:

WindowWithScrollBars wwsb;

 

printNameAndDisplay(wwsb);

參數(shù)w將被構(gòu)造為一個(gè)Window對(duì)象——還記得么?它是通過(guò)傳值方式傳入的。這里,使wwsb具體化的獨(dú)有信息將被截掉。無(wú)論傳入函數(shù)的對(duì)象的具體類型是什么,在printNameAndDisplay的內(nèi)部,w將總保有一個(gè)Window類的對(duì)象的身份(因?yàn)樗旧砭褪且粋€(gè)Window的對(duì)象)。特別地,在printNameAndDisplay內(nèi)部對(duì)display的調(diào)用總是Window::display,而永遠(yuǎn)不會(huì)是WindowWithScrollBars::display

解決截?cái)鄦?wèn)題的方法是:通過(guò)引用常量傳參:

void printNameAndDisplay(const Window& w)

{                                  // 工作正常,參數(shù)將不會(huì)被截?cái)唷?/span>

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

  w.display();

}

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

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

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

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

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

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

時(shí)刻牢記

盡量使用引用常量傳參,而不是傳值方式。因?yàn)橐话闱闆r下傳引用更高效,而且可以避免“截?cái)鄦?wèn)題”。

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

posted on 2007-06-01 18:12 ★ROY★ 閱讀(1450) 評(píng)論(3)  編輯 收藏 引用 所屬分類: Effective C++

評(píng)論

# re: 【翻譯】[Effective C++第三版?中文版][第20條]盡量使用“引用常量”傳參,而不是傳值  回復(fù)  更多評(píng)論   

好漂亮的程序啊!
2007-06-02 09:16 | 深藍(lán)色的音符

# re: 【翻譯】[Effective C++第三版?中文版][第20條]盡量使用“引用常量”傳參,而不是傳值  回復(fù)  更多評(píng)論   

給你做了個(gè)鏈接,希望以后能跟你多多交流.
因?yàn)槲椰F(xiàn)在也在開始學(xué)習(xí)C++,不過(guò)好難啊!
2007-06-02 13:04 | 深藍(lán)色的音符

# re: 【翻譯】[Effective C++第三版?中文版][第20條]盡量使用“引用常量”傳參,而不是傳值  回復(fù)  更多評(píng)論   

說(shuō)的很對(duì)
2007-06-04 14:02 | picasa
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            国产精品美女诱惑| 欧美成人激情视频免费观看| 亚洲精品国产日韩| 免费观看日韩| 亚洲精品视频在线播放| 亚洲高清av| 欧美成人午夜| 亚洲图片激情小说| 亚洲综合精品自拍| 国产在线视频不卡二| 久久综合网hezyo| 久久色在线观看| 亚洲精品一区二| 亚洲最新色图| 国产深夜精品| 欧美激情视频一区二区三区免费| 亚洲成人资源网| 亚洲精品在线视频观看| 国产精品久久| 久久天天躁夜夜躁狠狠躁2022| 久久午夜视频| 国产精品99久久久久久宅男| 亚洲一区二区三区视频播放| 激情久久综艺| 亚洲精品一区二区三区不| 国产精品免费视频xxxx | 久久av一区二区三区| 亚洲第一区中文99精品| 99re66热这里只有精品4| 国产婷婷色一区二区三区| 亚洲国产精品va| 国产精品视频免费观看| 亚洲第一福利视频| 国产伦精品一区二区三区免费| 蜜臀99久久精品久久久久久软件| 欧美日韩亚洲激情| 蜜桃av一区| 国产精品视频999| 亚洲国产精品www| 国外成人网址| 亚洲无限av看| 99精品视频免费| 久久久久国色av免费观看性色| 亚洲桃花岛网站| 久久久999| 久久精品国产99国产精品| 欧美日韩在线一二三| 蜜桃久久精品一区二区| 国产精品视频免费观看www| 亚洲激情午夜| 亚洲国产专区| 久久亚洲一区二区三区四区| 欧美专区在线| 国产精品久久久久天堂| 日韩一级黄色av| 亚洲日本电影在线| 久久综合久久综合这里只有精品 | 国产欧美一区二区视频| 夜夜爽99久久国产综合精品女不卡| 亚洲国产裸拍裸体视频在线观看乱了中文 | 性xx色xx综合久久久xx| 欧美三区在线| 亚洲激情综合| 91久久夜色精品国产九色| 久久久久久夜| 免费国产一区二区| 国语自产在线不卡| 久久国产主播精品| 久久女同互慰一区二区三区| 国产一级揄自揄精品视频| 午夜精品成人在线| 欧美在线免费视频| 国产一区二区三区高清播放| 午夜久久资源| 久久久久久网址| 欧美在线欧美在线| 欧美高清在线精品一区| 亚洲高清网站| 免费一级欧美在线大片| 亚洲国内高清视频| 一区二区精品在线| 国产精品igao视频网网址不卡日韩 | 国产午夜精品美女毛片视频| 午夜精品久久久久久久久久久久久| 亚洲欧美激情一区二区| 国产日韩欧美麻豆| 久久裸体艺术| 亚洲激情av在线| 亚洲一区二区三区精品在线| 国产乱码精品一区二区三| 欧美一区国产二区| 亚洲高清不卡| 亚洲欧美在线一区二区| 国产亚洲欧美aaaa| 另类尿喷潮videofree | 久久经典综合| 亚洲国产欧美一区| 国产精品va在线| 久久av一区二区三区| 亚洲国产精品久久人人爱蜜臀| 亚洲视频一区在线| 国产日韩亚洲| 欧美成人免费一级人片100| 在线视频免费在线观看一区二区| 欧美在线不卡| 亚洲精品裸体| 国产精品影视天天线| 狼人天天伊人久久| 亚洲视频香蕉人妖| 欧美承认网站| 午夜精品剧场| 亚洲人成小说网站色在线| 国产精品亚发布| 欧美大片国产精品| 欧美一区二区三区在| 日韩亚洲成人av在线| 麻豆精品91| 性做久久久久久久免费看| 亚洲高清视频在线观看| 国产精品一区=区| 欧美不卡一区| 久久久久久网站| 亚洲欧美日韩综合| 99在线精品观看| 欧美国产在线视频| 久久久久久一区二区| 亚洲欧美国内爽妇网| 亚洲伦理在线观看| 亚洲高清av| 韩国精品一区二区三区| 国产欧美日韩免费| 国产精品高精视频免费| 欧美日韩国产123| 麻豆精品视频在线观看| 久久久久综合一区二区三区| 亚洲欧美日韩在线播放| 一区二区三区欧美在线观看| 亚洲国内自拍| 亚洲国产视频一区| 欧美jizzhd精品欧美喷水 | 亚洲精品美女久久久久| 亚洲国产美女| 在线观看亚洲| 伊人一区二区三区久久精品| 国产尤物精品| 欧美日韩综合| 欧美在线91| 欧美一区二区三区的| 欧美一区二区视频在线| 欧美一区二区三区成人| 午夜精品婷婷| 欧美亚洲一区| 久久九九全国免费精品观看| 久久久精品视频成人| 久久精品欧美日韩精品| 久久婷婷丁香| 久久综合国产精品| 欧美国产精品v| 欧美精品三级| 国产精品高潮在线| 国产农村妇女精品一二区| 国内揄拍国内精品久久| 亚洲国产精品一区二区第四页av | 欧美大胆a视频| 欧美日韩黄视频| 国产精品视频yy9099| 狠狠色狠狠色综合| 亚洲精品视频免费在线观看| 亚洲一区二区三区视频| 欧美在线视频a| 欧美高清你懂得| 99riav久久精品riav| 欧美一二三区精品| 久热精品在线视频| 欧美日韩在线第一页| 激情欧美日韩| 99国产精品视频免费观看| 午夜欧美精品| 欧美大片18| 一本久道综合久久精品| 久久精品91| 欧美日韩国产成人在线免费| 国产一区日韩二区欧美三区| 亚洲欧洲在线免费| 欧美一区中文字幕| 亚洲第一精品夜夜躁人人躁 | 久久久一本精品99久久精品66| 亚洲国产日韩欧美综合久久| 亚洲欧美日韩另类| 欧美精品激情在线观看| 国产一本一道久久香蕉| 一本久道久久综合狠狠爱| 久久久久久久久久久久久女国产乱| 亚洲成人自拍视频| 亚洲综合色在线| 欧美日韩综合久久| 亚洲黄一区二区三区| 欧美亚洲免费| 一本到高清视频免费精品| 麻豆av福利av久久av|