2011-10-08 223 views
4

我們有淺拷貝深拷貝誰可以爲我們做這項工作,當我們想要在C++中複製對象。所以,
什麼是懶惰副本
這是一個由程序員或編譯器自己照顧的東西嗎?
什麼是懶惰副本有利的編程方案?爲什麼懶的拷貝時我們有深拷貝和淺拷貝?

+3

你試過維基百科? http://en.wikipedia.org/wiki/Object_copy – phooji

+6

我想你已經Google了,並且發現這個:[link](http://en.wikipedia.org/wiki/Object_copy#Lazy_copy)? –

+1

爲什麼這個問題被低估了很多次?至少,一些Q是有效的Q。 –

回答

0

我不確定你的意思是「有淺薄和深層的複製人可以爲我們做這項工作」。當你編寫你的拷貝構造函數和賦值操作符時,你需要做出決定,決定你想如何創建一個拷貝。

在淺拷貝中,您只需直接複製對象成員。如果這些成員指向堆內存,則副本指向堆內存的同一塊。如果您不提供複製構造函數,這是C++執行的默認複製。

在深度複製中,由成員指針指向的任何內存本身都被複制(也可能在這些對象的成員上遞歸)。

在一個懶惰的副本中,你從一個淺拷貝開始。如果對象或它的孩子從不修改,那麼你很好。無需再創建堆內存的第二個副本。當兩個副本中的任何一個被修改時,首先執行深層複製,以便修改不會應用於這兩個對象。這也被稱爲coopy-on-write。

延遲複製的目的是獲得深度複製的外觀,以及淺拷貝的一些性能優勢。這是否最終取決於對象的使用情況。如果你打算修改一個對象的許多副本,那麼你很可能會看到這些優點。如果大多數物體最終都會被修改,那麼優點就會消失。當對象被非常頻繁地修改時,在修改對象之前檢查深度複製的開銷使得它比只是簡單的深層複製更糟糕。

字符串經常被認爲是懶惰複製的好地方,因爲很多時候複製只是爲了在不同的地方顯示,但大多數字符串無論如何都使用深度複製,或者使用淺拷貝,並且完全不允許修改。

+1

我認爲OP的問題是爲什麼在已經有兩種淺層和深層複製機制的情況下使用Lazy Copy。 –

+0

copy-on-write會導致C++中的身份問題。只要訪問子對象,懶惰複製計劃就必須複製副本,而不僅僅是修改。 –

1

懶副本大致是:

  • 執行淺拷貝馬上
  • 但後來執行深拷貝,只有當它成爲絕對必要的(即當對象將要進行修改),在希望這時刻永遠不會到來。

所以他們是不同的概念。延遲拷貝本質上是一個運行時優化,而淺/深拷貝是一個編譯時構造,可以用來實現懶惰拷貝,但也可以獨立使用。

5

什麼是懶惰拷貝?

Wikipedia恰當地定義這一點。

懶惰副本是淺拷貝和Deep Copy的組合。最初複製對象時,使用(快速)淺拷貝。計數器也用於跟蹤多少個對象共享數據。當程序想要修改一個對象時,它可以確定數據是否共享(通過檢查計數器),並且可以在必要時進行深層複製。 懶惰副本只是作爲深層副本看起來像外部,但只要有可能就利用淺拷貝的速度。由於櫃檯價格的不利因素,而且價格偏高,但基礎成本不變。另外,在某些情況下,循環引用也會導致問題。

這是一個由程序員照顧的東西,還是編譯器自己做的事情?

程序員必須爲他自己的類實現這種行爲。
默認情況下,編譯器在複製功能中執行淺拷貝(複製構造函數&賦值運算符)。
Deep Copy是程序員必須爲他的類實現的功能,因此可以對複製函數進行特殊的成員處理(指針)。

什麼是懶惰副本有利的編程方案?

理想情況下,
一種情形,其中,複製對象導致的性能損失,但對象不被修改非常頻繁懶惰拷貝將在性能方面是有利的。

維基百科援引其中,懶惰複製(寫時複製)使用number of examples

+2

其中的缺點:它表明,由於共享計數器,COW在多線程(在多核上)時效果不佳。必須保持計數器在各種核心的緩存中同步,這會引起爭用。 –

0

當您的可能通常需要Deep Copy,但不確定是否真的有必要時,使用延遲複製。深度複製通常是一項昂貴的操作。如果你在100%的情況下無條件地完成它,然後發現你只需要10%的對象,那麼在其他90%的對象上進行深度複製的努力就被​​浪費了。

這是當懶惰複製進來。懶惰複製是推遲延遲點播版本深複製的。使用延遲複製,您不會立即執行深度複製。相反,你準備(或時間表)的深度複製通過存儲在接收者對象(其中大部分時間歸結爲一個單純的淺複製)所有相關信息,並等待,直到它成爲已知的深層副本是否是真的這個特定對象是必需的。如果事實證明是必要的,則執行實際的Deep Copy。如果對Deep Copy的需求永遠不會發生,那麼就不會發生,從而爲您節省了工作量。

0

讓我談談C++

一個在C++中非常重要的部分寫入類是實現拷貝構造函數和重載=運算符的功能。

這對需要寫這些功能,以使你的程序更有效的教程會談。在進入這個概念之前讓我們瞭解一些基本的術語。

構造函數:它是創建類對象時調用的特殊函數。理想情況下,構造函數必須包含初始化類的數據成員的邏輯。

複製構造函數:它在創建時和對象初始化時被調用。當調用複製構造函數時,存在更多的場景。

運算符函數:C++允許在運算符關鍵字的幫助下重載運算符。這有助於我們將用戶定義的類型視爲基本類型。

由編譯器插入的默認拷貝構造函數和=運算符函數,當它們從類中丟失時。它執行位模式複製,即將一個對象的數據成員簡單地複製到另一個對象中。

考慮下面的代碼示例

class CSample 
{   
    int x; 
    public: 
    //dafualt constructor 
     CSample(): x(0){}   
     int GetX() 
     { 
     return x; 
     } 
    }; 

int main() 
{ 
    CSample ob1; //Default constructor is called. 
    CSample ob2 = ob1; //default copy constructor called. 

    CSample ob3; //Default constructor called. 
    ob3 = ob1; //default overloaded = operator function called. 

} 

在上面的例子

CSample ob2 = ob1; 
//This line will copy the bit pattern of ob1 in ob2 so the data member 
// x in both the object will contain same value i.e 0. 

類似地陳述

ob3 = ob1; 
//This line will copy the bit pattern of ob1 in ob2 so the data member 
// x in both the object will contain same value i.e 0. 

如預期上面的代碼將工作,直到類構件不分配任何資源(文件或內存) 。考慮一下類如下更新的場景。

 class CSample 
    { 
     int *x; 
     int N; 
    public: 
     //dafualt constructor 
     CSample(): x(NULL){}   
     void AllocateX(int N) 
     { 
      this->N = N; 
      x = new int[this->N]; 
     } 
     int GetX() 
     { 
     return x; 
     } 
     ~CSample() 
     { 
     delete []x; 
     } 
    }; 

    int main() 
    { 
    CSample ob1; //Default constructor is called. 
    ob1.AllocateX(10); 

    //problem with this line 
    CSample ob2 = ob1; //default copy constructor called. 

    CSample ob3; //Default constructor called. 

    //problem with this line 
    ob3 = ob1; //default overloaded = operator function called. 
    } 

    class CSample 
    { 
    int *x; 
    int N; 
public: 
    //dafualt constructor 
    CSample(): x(NULL) 
    {}   
    //copy constructor with deep copy 
    CSample(const CSample &ob) 
    { 
     this->N = ob.N: 
     this->x = new int[this->N]; 
    } 
     //=operator function with deep copy. 
    void operator=(const CSample &ob) 
    { 
     this->N = ob.N: 
     this->x = new int[this->N]; 

    } 

    void AllocateX(int N) 
    { 
     this->N = N; 
     x = new int[this->N]; 
    } 
    int GetX() 
    { 
    return x; 
    } 
    ~CSample() 
    { 
    delete []x; 
    } 
};