C++對象模型(三):Program Transformation Semantics (程序轉換語義學)

本文是Inside The C++ Object Model Chapter 2 部分的讀書筆記。是討論編譯器調用拷貝構造函數時的策略(如何優化以提升效率),侯捷稱之爲"程序轉化的語義學"ide

或者說是是關於編譯器對於程序是如何進行有效轉化或者說翻譯,以實現C++的語法機制。主要來講有如下幾種Semantics:函數

1) 明確的初始化操做(Explicit Initialization)優化

好比定義: X x0;
那麼如下定義: X x1(x0); X x2 = x0; X x3 = X(x0); 都會被轉化成: X x1,x2,x3; 在這裏編譯器並不會作這三個object的初始化,而是調用copy constructor進行初始化:.net

x1.X::X(x0); x2.X::X(x0); x3.X::X(x0);翻譯


2) 參數初始化(Argument Initialization)設計

C++ Standard ( Section 8.5)說,把一個class  object 當作參數傳遞給一個函數或者把它做爲一個函數的返回值時,至關於如下形式的初始化操做:ip

X xx = arg;其中xx是形式參數或者返回值,arg表明真正的參數值,所以相似於void foo(X x0);這種調用,將會使得local instance x0以memberwise的形式以實際參數爲初始值進行初始化。ci

通常來講,編譯器有兩種作法:get

a) introduce a temporary object編譯器

仍是以上文的函數聲明 void foo(X x0);

調用進入後,一、編譯器生成一個temporary object:X _temp;

                       二、以實際參數xx 拷貝構造 這個temporary object:_temp.X::X(xx);

                       三、從新改寫函數調用操做,foo(_temp);

                       四、最重要的一點就是修改參數調用方式爲引用,不然如何工做又回到原點啦。。。void foo(X &x0);

b) 將參數直接以copy constructor建構到函數的堆棧上,這樣也會有一個local object生成;固然在函數返回時該local object也會被destructed。


3) 返回值的初始化(Return Value Initialization)

當返回值是object時,這個object是如何返回的呢?cfront使用的是一個雙階段轉化:

a) 首先加上一個額外的參數,是class object的reference,這個參數將放置經過copy constructor得來的返回值

b)在return以前安插一個copy constructor,以便將欲傳回之的object當作上述新增參數的處置。


例如:X bar() { X xx; return xx;} 會被轉化爲:

void bar(X & _res)      //這裏安插了臨時引用參數

{

X xx;

xx.X::X();

_res.X::X(xx);              //這裏安插了臨時引用的拷貝構造函數

return;

}

如今編譯器必須轉化每一個bar調用,以反映其新定義。例如X xx = bar(); ===> X xx; bar( xx );

而相應的 bar().memfunc(); //執行bar()所返回之X class object的member function

會被編譯器轉化爲:

X temp0;

(bar(temp0),temp0).memfunc();


在返回值優化上,Optimization at the User Level or Optimization at the Compiler Level。在User Level, 設計者須要建立不一樣的constructor,這樣object直接經過計算,而不須要copy constructor。這樣作若是在很是注重效率的場合可能比較有意義,可是缺少抽象。

在Compiler Level,如今廣爲認知的就是 Name Return Value(NRV)Optimization:

void bar(X & _res)      //這裏安插了臨時引用參數

{

_res.X::X();

//直接操做_res

return;

}


也就是說,NRVO 省略了一次copy constructor的調用。可是若是copy constructor有side-effect的話,那麼這個優化就會有問題。

        書中提到,若是某個class 會有大量的object return value的狀況,那麼須要爲該class define copy constructor,以觸發NRV(或者叫RVO, Return Value Optimization)。可是,黃俊達先生認爲:Lippman 在 p67 最後一行所言『這個程式的第一個版本不能實施 NRV 最佳化,由於 test class 缺乏一個 copy constructor』,
此語錯誤。黃先生認爲若是程式沒有 explicit copy constructor,編譯器會自動爲咱們作出來(如爲 trivial,則直接 bitwise copy;如爲 nontrivial,則由編譯器爲咱們合成出一個 copy constructor)。所以,有沒有 explicit copy constructor 並不影響 NRV 最佳化的實施。他認爲 NRV 最佳化主要是 由編譯器 option 來決定要不要實施。他而且作了一些實驗,判斷 VC 和 gcc 都沒有作到 NRV 最佳化,而其不作的理由不是由於技術上的困難,是爲了不形成「user defined copy constructor 之反作用失效」-- 所謂反作用
是指,例如「在 user defined copy constructor 中作一個 cout 輸出」之類這種「與 memberwise copy 無關」的動做。

NRV優化仍是很重要,好比下面的代碼,若是沒有NRV將會有三次copy 構造,二次析構:
        Type get(int I) { return Type(i); } Type t = get(1);

甚至有人認爲user defined copy constructor會阻止NRV的優化。更多討論能夠參見:關於編譯器對拷貝構造函數優化的問題再討論

相關文章
相關標籤/搜索