亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C++箴言:用傳引用給const取代傳值

2019-11-17 05:39:07
字體:
來源:轉載
供稿:網友

  缺省情況下,C++ 以傳值方式將對象傳入或傳出函數(這是一個從 C 繼續來的特性)。除非你非凡指定其它方式,否則函數的參數就會以實際參數(actual argument)的拷貝進行初始化,而函數的調用者會收到函數返回值的一個拷貝。這個拷貝由對象的拷貝構造函數生成。這就使得傳值(pass-by-value)成為一個代價不菲的操作。例如,考慮下面這個類層級結構:

class Person {
  public:
   Person(); // parameters omitted for simplicity
   virtual ~Person(); // see Item 7 for why this is virtual
   ...

  PRivate:
   std::string name;
   std::string address;
};

class Student: public Person {
  public:
   Student(); // parameters again omitted
   ~Student();
   ...

  private:
   std::string schoolName;
   std::string schoolAddress;
};

  現在,考慮以下代碼,在此我們調用一個函數—— validateStudent,它得到一個 Student 參數(以傳值的方式),并返回它是否驗證有效的結果:

bool validateStudent(Student s); // function taking a Student
// by value

Student plato; // Plato studied under Socrates

bool platoIsOK = validateStudent(plato); // call the function

  當這個函數被調用時會發生什么呢?

  很明顯,Student 的拷貝構造函數被調用,用 plato 來初始化參數 s。同樣明顯的是,當 validateStudent 返回時,s 就會被銷毀。所以這個函數的參數傳遞代價是一次 Student 的拷貝構造函數的調用和一次 Student 的析構函數的調用。

  但這還不是全部。一個 Student 對象內部包含兩個 string 對象,所以每次你構造一個 Student 對象的時候,你也必須構造兩個 string 對象。一個 Student 對象還要從一個 Person 對象繼續,所以每次你構造一個 Student 對象的時候,你也必須構造一個 Person 對象。一個 Person 對象內部又包含兩個額外的 string 對象,所以每個 Person 的構造也承擔著另外兩個 string 的構造。最終,以傳值方式傳遞一個 Student 對象的后果就是引起一次 Student 的拷貝構造函數的調用,一次 Person 的拷貝構造函數的調用,以及四次 string 的拷貝構造函數調用。當 Student 對象的拷貝被銷毀時,每一個構造函數的調用都對應一個析構函數的調用,所以以傳值方式傳遞一個 Student 的全部代價是六個構造函數和六個析構函數!

  好了,這是正確的和值得的行為。究竟,你希望你的全部對象都得到可靠的初始化和銷毀。盡管如此,假如有一種辦法可以繞過所有這些構造和析構過程,應該變得更好,這就是:傳引用給 const(pass by reference-to-const):

bool validateStudent(const Student& s);
  這樣做非常有效:沒有任何構造函數和析構函數被調用,因為沒有新的對象被構造。被修改的參數聲明中的 const 是非常重要的。 validateStudent 的最初版本接受一個 Student 值參數,所以調用者知道它們屏蔽了函數對它們傳入的 Student 的任何可能的改變;validateStudent 也只能改變它的一個拷貝。現在 Student 以引用方式傳遞,同時將它聲明為 const 是必要的,否則調用者必然擔心 validateStudent 改變了它們傳入的 Student。

  以傳引用方式傳遞參數還可以避免切斷問題(slicing problem)。當一個派生類對象作為一個基類對象被傳遞(傳值方式),基類的拷貝構造函數被調用,而那些使得對象的行為像一個派生類對象的非凡特性被“切斷”了。你只剩下一個純粹的基類對象——這沒什么可吃驚的,因為是一個基類的構造函數創建了它。這幾乎絕不是你希望的。例如,假設你在一組實現一個圖形窗口系統的類上工作:

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 函數得到它,而且所有的窗口都可以顯示,你可一個通過調用 display 函數來做到這一點。display 為 virtual 的事實清楚地告訴你:一個純粹的基類的 Window 對象的顯示方法有可能不同于專門的 WindowWithScrollBars 對象的顯示方法。

  現在,假設你想寫一個函數打印出一個窗口的名字,并隨后顯示這個窗口。以下這個函數的寫法是錯誤的:

void printNameAndDisplay(Window w) // incorrect! parameter
{
  // may be sliced!
  std::cout << w.name();
  w.display();
}

  考慮當你用一個 WindowWithScrollBars 對象調用這個函數時會發生什么:

WindowWithScrollBars wwsb;

printNameAndDisplay(wwsb);

  參數 w 將被作為一個 Window 對象構造——它是被傳值的,記得嗎?而且使 wwsb 表現得像一個 WindowWithScrollBars 對象的非凡信息都被切斷了。在 printNameAndDisplay 中,全然不顧傳遞給函數的那個對象的類型,w 將始終表現得像一個 Window 類的對象(因為它就是一個 Window 類的對象)。非凡是,在 printNameAndDisplay 中調用 display 將總是調用 Window::display,絕不會是 WindowWithScrollBars::display。

  繞過切斷問題的方法就是以傳引用給 const 的方式傳遞 w:

void printNameAndDisplay(const Window& w) // fine, parameter won’t
{
  // be sliced
  std::cout << w.name();
  w.display();
}

  現在 w 將表現得像實際傳入的那種窗口。

  假如你掀開編譯器的蓋頭偷看一下,你會發現用指針實現引用是非常典型的做法,所以以引用傳遞某物實際上通常意味著傳遞一個指針。由此可以得出結論,假如你有一個內建類型的對象(例如,一個 int),以傳值方式傳遞它經常比傳引用方式更高效。那么,對于內建類型,當你需要在傳值和傳引用給 const 之間做一個選擇時,沒有道理不選擇傳值。同樣的建議也適用于 STL 中的迭代器(iterators)和函數對象(function objects),因為,作為慣例,它們就是為傳值設計的。迭代器(iterators)和函數對象(function objects)的實現有責任保證拷貝的高效并且不受切斷問題的影響。(這是一個“規則如何變化,依靠于你使用 C++ 的哪一個部分”的實例。)

  內建類型很小,所以有人就斷定所有的小類型都是傳值的上等候選者,即使它們是用戶定義的。這樣的推論是不可靠的。僅僅因為一個對象小,并不意味著調用它的拷貝構造函數就是廉價的。很多對象——大多數 STL 容器也在其中——容納的和指針一樣,但是拷貝這樣的對象必須同時拷貝它們指向的每一樣東西。那可能是非常昂貴的。

  即使當一個小對象有一個廉價的拷貝構造函數,也會存在性能問題。一些編譯器對內建類型和用戶定義類型并不一視同仁,即使他們有同樣的底層表示。例如,一些編譯器拒絕將僅由一個 double 組成的對象放入一個寄存器中,即使在常規上它們非常愿意將一個純粹的 double 放入那里。假如發生了這種事情,你以傳引用方式傳遞這樣的對象更好一些,因為編譯器理所當然會將一個指針(引用的實現)放入寄存器。

  小的用戶定義類型不一定是傳值的上等候選者的另一個原因是:作為用戶定義類型,它的大小經常變化。一個現在較小的類型在將來版本中可能變得更大,因為它的內部實現可能會變化。甚至當你換了一個不同的 C++ 實現時,事情都可能會變化。例如,就在我這樣寫的時候,一些標準庫的 string 類型的實現的大小就是另外一些實現的七倍。

  通常情況下,你能合理地假設傳值廉價的類型僅有內建類型及 STL 中的迭代器和函數對象類型。對其他任何類型,請遵循本 Item 的建議,并用傳引用給 const 取代傳值。

  Things to Remember

  ·用傳引用給 const 取代傳值。典型情況下它更高效而且可以避免切斷問題。

  ·這條規則并不適用于內建類型及 STL 中的迭代器和函數對象類型。對于它們,傳值通常更合適。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩av手机在线| 91chinesevideo永久地址| 国产精品高潮呻吟久久av黑人| 亚洲综合色激情五月| 欧美成人激情在线| 国产视频久久久久| 欧美日韩爱爱视频| 最近2019中文字幕在线高清| 亚洲免费av网址| 少妇高潮久久77777| 日韩视频免费在线观看| 欧美激情亚洲一区| 亚洲欧美一区二区三区情侣bbw| 久热爱精品视频线路一| 日韩美女在线观看| 成人黄色在线播放| 日韩中文字幕网站| 91高清视频在线免费观看| 亚洲开心激情网| 国产999在线| 国产精品美女主播在线观看纯欲| 日韩在线观看免费网站| 亚洲欧洲偷拍精品| 亚洲欧美日本另类| www.国产精品一二区| 国产精品久久9| 91丝袜美腿美女视频网站| 国产精品美女久久久久久免费| 在线精品高清中文字幕| 亚洲电影免费在线观看| 亚州欧美日韩中文视频| 亚洲欧美国产另类| 亚洲xxxxx电影| 黑人狂躁日本妞一区二区三区| 91精品国产综合久久香蕉的用户体验| 欧美日韩国产激情| 日本精品久久久| 国产综合在线看| 欧美专区在线观看| 中文字幕精品视频| 日韩av色综合| 亚洲国产天堂久久综合| 永久免费看mv网站入口亚洲| 国产成人精品视频在线观看| 国产精品中文在线| 国产成人一区二区三区电影| 亚洲一区二区三区成人在线视频精品| 在线观看精品国产视频| 欧美二区在线播放| 久久久电影免费观看完整版| 欧美午夜精品久久久久久人妖| 久久久国产91| 精品一区二区三区四区| 日韩精品免费在线观看| 91美女片黄在线观| 欧美影院在线播放| 久久国产精品久久久| 国产这里只有精品| 亚洲精品98久久久久久中文字幕| 国产久一一精品| 日韩av在线精品| 国产精品久久久久一区二区| 欧美成人精品激情在线观看| 91精品久久久久久久久中文字幕| 国产精品免费福利| 91精品国产综合久久香蕉| 日本成人激情视频| 亚洲欧美日韩第一区| 欧美成人精品不卡视频在线观看| 81精品国产乱码久久久久久| 精品无人区太爽高潮在线播放| 日韩精品在线免费观看视频| 亚洲老头同性xxxxx| 久久久久久久久久婷婷| 成人黄色免费片| 亚洲国产精品999| 国产日韩欧美日韩大片| 色播久久人人爽人人爽人人片视av| 欧美激情亚洲国产| 国模精品视频一区二区三区| 国产精品入口免费视| 久久久中文字幕| 久热在线中文字幕色999舞| 欧美视频在线观看免费网址| 久久男人资源视频| 国产99久久久欧美黑人| 午夜精品理论片| 一本大道香蕉久在线播放29| 国产精品久久999| 欧美电影免费观看大全| 日韩成人av网| 欧洲s码亚洲m码精品一区| 久久天天躁日日躁| 91国内精品久久| 热re91久久精品国99热蜜臀| 亚洲香蕉av在线一区二区三区| 日韩美女在线观看一区| 亚洲japanese制服美女| 亚洲国内精品在线| 精品久久久久久国产91| 亚洲男人天堂久| 国产精品专区h在线观看| 亚洲精品视频在线播放| 国产国产精品人在线视| 91九色综合久久| 国产欧美日韩精品在线观看| 136fldh精品导航福利| 国内精品400部情侣激情| 精品久久香蕉国产线看观看gif| 欧美中文字幕在线| 性欧美在线看片a免费观看| 日韩中文字幕在线视频播放| 国产精品久久中文| 国产欧美日韩精品丝袜高跟鞋| 韩国国内大量揄拍精品视频| 亚洲日本中文字幕免费在线不卡| 日本一区二区在线免费播放| 国产精品永久在线| 中文字幕亚洲字幕| 日日噜噜噜夜夜爽亚洲精品| 国产精品一区二区av影院萌芽| 在线精品视频视频中文字幕| 欧美日韩国产在线播放| 欧美国产日韩一区二区| 久久久国产影院| 另类少妇人与禽zozz0性伦| 欧美日本中文字幕| 亚洲自拍另类欧美丝袜| 国产精品视频午夜| 亚洲国产精品人人爽夜夜爽| 亚洲国产天堂久久国产91| 色综合亚洲精品激情狠狠| 国产在线观看一区二区三区| 欧美老妇交乱视频| 久久天堂av综合合色| 日韩av三级在线观看| 久久国产视频网站| 日韩精品欧美国产精品忘忧草| www.日韩欧美| 欧美福利视频网站| 91av视频在线免费观看| 亚洲精品免费一区二区三区| 久久久亚洲精品视频| 91精品国产高清| 米奇精品一区二区三区在线观看| 久久久久这里只有精品| 久久久精品国产一区二区| 九九精品在线视频| 97精品国产97久久久久久春色| 成人久久久久久久| 伊人久久大香线蕉av一区二区| 亚洲老头老太hd| 亚洲最大激情中文字幕| 国产一区二区三区在线免费观看| 国产精品www网站| 91精品视频播放| 国产成人亚洲综合青青| 亚洲自拍偷拍一区| 在线观看日韩av| 国产国语刺激对白av不卡| 九色精品免费永久在线| 国产精品老牛影院在线观看| 国语自产精品视频在线看一大j8| 日韩精品视频中文在线观看|