2010-01-27 64 views
29

我在讀Copy and Swap什麼是複製elision以及它如何優化複製和交換習慣用法?

我嘗試閱讀Copy Elision上的一些鏈接,但無法正確理解它的含義。有人可以解釋一下這種優化是什麼,特別是以下文字的意思是什麼

這不僅僅是一個方便的問題,實際上是一種優化。如果參數綁定到一個左值(另一個非const對象),則在創建參數時會自動創建該對象的副本。但是,當s綁定到右值(臨時對象,文字)時,副本通常會被省略,這會保存對複製構造函數和析構函數的調用。在參數被接受爲常量引用的賦值運算符的早期版本中,當引用綁定到右值時,複製elision不會發生。這導致一個額外的對象被創建和銷燬。

+0

相關:[什麼是複製elision?](http://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization) – 2015-01-13 07:22:51

回答

33

存在複製構造函數以進行復制。從理論上講,當你寫這樣一行:

CLASS c(foo()); 

,編譯器將不得不調用拷貝構造函數的foo()返回複製到c

複製elision是一種跳過調用複製構造函數以免支付開銷的技術。

例如,編譯器可以安排foo()將直接構造其返回值到c

這是另一個例子。比方說,你有一個函數:

void doit(CLASS c); 

如果與實際的參數調用它,編譯器調用拷貝構造函數,以便原始參數不能被修改:

CLASS c1; 
doit(c1); 

但現在考慮不同的例子,假設你打電話給你的功能是這樣的:

doit(c1 + c1); 

operator+將不得不創建一個臨時對象(右值)。代替在調用doit()之前調用複製構造函數,編譯器可以傳遞由operator+創建的臨時文件,並將其傳遞給doit()

2

下面是一個例子:

#include <vector> 
#include <climits> 

class BigCounter { 
public: 
    BigCounter &operator =(BigCounter b) { 
     swap(b); 
     return *this; 
    } 

    BigCounter next() const; 

    void swap(BigCounter &b) { 
     vals_.swap(b); 
    } 

private: 
    typedef ::std::vector<unsigned int> valvec_t; 
    valvec_t vals_; 
}; 

BigCounter BigCounter::next() const 
{ 
    BigCounter newcounter(*this); 
    unsigned int carry = 1; 
    for (valvec_t::iterator i = newcounter.vals_.begin(); 
     carry > 0 && i != newcounter.vals_.end(); 
     ++i) 
    { 
     if (*i <= (UINT_MAX - carry)) { 
     *i += carry; 
     } else { 
     *i += carry; 
     carry = 1; 
     } 
    } 
    if (carry > 0) { 
     newcounter.vals_.push_back(carry); 
    } 
    return newcounter; 
} 

void someFunction() 
{ 
    BigCounter loopcount; 
    while (true) { 
     loopcount = loopcount.next(); 
    } 
} 

somefunction從複製省略線路loopcount = loopcount.next();好處很大。如果不允許複製elision,則該行將需要3次調用複製構造函數和一個相關聯的調用到析構函數。如果允許使用副本刪除,則可以將其減少到複製構造函數的一個調用,即BigCount::next()內部的顯式調用,其中聲明瞭newcounter

如果operator =已宣佈並這樣定義:

BigCounter &BigCounter::operator =(const BigCounter &b) { 
    BigCounter tmp(b); 
    swap(tmp); 
    return *this; 
} 

有能有我們一直拷貝構造函數的調用2,即使複製省略。一個構造newcounter,另一個構造tmp。如果沒有複製elision,那麼仍然會有3.這就是爲什麼聲明operator =以便其參數需要調用複製構造時,對賦值運算符使用「複製和交換」慣用法時可以進行優化。當調用複製構造函數來構造參數時,它的調用可能會被忽略,但如果它被調用來創建局部變量,它可能不會被調用。

相關問題