[英]What is copy elision and how does it optimize the copy-and-swap idiom?
我正在閱讀復制和交換 。
我嘗試閱讀Copy Elision上的一些鏈接,但無法弄清楚它的含義。 有人可以解釋一下這種優化是什么,特別是下面的文字是什么意思
這不僅僅是為了方便,而且實際上是一種優化。 如果參數綁定到左值(另一個非常量對象),則在創建參數時會自動創建對象的副本。 但是,當s綁定到rvalue(臨時對象,文字)時,通常會省略該副本,從而保存對復制構造函數和析構函數的調用。 在賦值運算符的早期版本中,參數被接受為const引用,當引用綁定到右值時,不會發生復制省略。 這導致創建和銷毀另外的對象。
存在復制構造函數以進行復制。 理論上,當你寫一行如:
CLASS c(foo());
編譯器必須調用復制構造函數將foo()
的返回值復制到c
。
復制省略是一種跳過調用復制構造函數的技術,以免支付開銷。
例如,編譯器可以安排foo()
將其返回值直接構造為c
。
這是另一個例子。 假設你有一個功能:
void doit(CLASS c);
如果使用實際參數調用它,編譯器必須調用復制構造函數,以便不能修改原始參數:
CLASS c1;
doit(c1);
但是現在考慮一個不同的例子,假設你像這樣調用你的函數:
doit(c1 + c1);
operator+
將要創建一個臨時對象(一個右值)。 編譯器可以傳遞由operator+
創建的臨時函數,而不是在調用doit()
之前調用復制構造函數,而是將其傳遞給doit()
。
這是一個例子:
#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();
復制省略大大受益。 如果不允許復制省略,那么該行將需要3次復制構造函數的調用以及對析構函數的相關調用。 隨着被允許復制省略,它可以降低到1調用拷貝構造函數中,明確一個內部的BigCount::next()
其中newcounter
聲明。
如果operator =
已聲明並定義如下:
BigCounter &BigCounter::operator =(const BigCounter &b) {
BigCounter tmp(b);
swap(tmp);
return *this;
}
即使使用copy elision,也必須進行2次復制構造函數的調用。 一個構建newcounter
,另一個構建tmp
。 如果沒有復制省略,那么仍然會有3.這就是為什么聲明operator =
所以它的參數需要調用復制結構可以是一個優化,當使用'復制和交換'習慣用於賦值運算符時。 當調用復制構造函數來構造一個參數時,它的調用可能會被省略,但如果它被調用來創建一個局部變量,它可能不會。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.