簡體   English   中英

什么是復制省略以及它如何優化復制和交換習慣用法?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM