2011-10-08 176 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; 
    } 
};