开发者

why lazy copy when we have deep copy and shallow copy?

开发者 https://www.devze.com 2023-04-11 11:36 出处:网络
We have shallow c开发者_如何学运维opy and deep copy who can do the job for us when we want to copy objects in C++. So,

We have shallow c开发者_如何学运维opy and deep copy who can do the job for us when we want to copy objects in C++. So,

What is Lazy copy?

Is this a thing that is taken care by a programmer or compiler does this on its own?

What are the programming scenarios where a lazy copy is advantageous?


What is Lazy Copy?

Wikipedia Defines this aptly.

A lazy copy is a combination of both shallow copy and Deep Copy. When initially copying an object, a (fast) shallow copy is used. A counter is also used to track how many objects share the data. When the program wants to modify an object, it can determine if the data is shared (by examining the counter) and can do a deep copy if necessary. Lazy copy looks to the outside just as a deep copy but takes advantage of the speed of a shallow copy whenever possible. The downside are rather high but constant base costs because of the counter. Also, in certain situations, circular references can also cause problems.

Is this a thing that is taken care by a programmer or something that the compiler does on its own?

The programmer has to implement this behavior for his own classes.
A compiler performs shallow copies in copying functions(copy constructor & assignment operator) by default.
Deep Copy is what a programmer has to implement for his class, so that the special handling of members(pointers) can be in place for copying functions.

What are the programming scenarios where a lazy copy is advantageous?

Ideally,
A situation wherein copying an object causes a performance penalty but the objects are not being modified very frequently the Lazy copy would be advantageous in terms of performance.

The Wikipedia cites a number of examples where, Lazy Copy(Copy On Write) is used.


Lazy copy is roughly:

  • perform shallow copy right away
  • but perform the deep copy later, only when it becomes absolutely necessary (i.e. when object is about to be modified), in hope this moment will never come.

So they are different concepts. Lazy copy is essentially a run-time optimization while shallow/deep copy is a compile-time construct that can be used to implement the lazy copy but can be used independently as well.


I'm not sure what you mean by "having shallow and deep copy who can do the job for us". Whe you write your copy constructor and assignment operator, you need to make the decision, on how you want to make a copy.

In shallow copy, you just copy the object members directly. If those members are pointers to heap memory, the copy points to the same block of heap memory. This is the default copy performed by C++ if you don't provide a copy constructor.

In a deep copy, any memory pointed to by member pointers is itself copied (potentially recursing on the members of those objects as well).

In a lazy copy, you start out with a shallow copy. If the object or its children are never modified, then you're fine. No need to make a second copy of the heap memory. When either of the two copies gets modified, a deep copy is first performed so that the modifications don't get applied to both objects. This is also known as coopy-on-write.

The purpose of lazy copying is to get the appearance of deep-copies, with some of the performance benefits of shallow copying. Whether this ends up being a performance gain depends on the usage of the objects. If you plan on having many copies of an object unmodified, then you're likely to see the advantages. If most objects are getting modified eventually anyway, then the advantages go away. When the objects get modified very frequently, the overhead of checking that the deep copy has been performed before modifying the object makes it perform worse than just a plain deep copy.

Strings are often cited as good places for lazy copying, since very often, copies are just made for displaying in different places, but most strings either use deep copies anyway, or use shallow copies, and disallow modification altogether.


Lazy Copy is used when you might generally need Deep Copy, but are not sure whether it is really necessary. Deep Copy is generally an expensive operation. If you do it unconditionally in 100% of cases and then discover that you only needed it in 10% of objects, then the efforts spent on Deep-Copying the other 90% of objects were wasted.

This is when Lazy Copy comes in. Lazy Copy is a postponed, delayed, on-demand version of Deep Copy. With Lazy Copy you don't perform Deep Copy right away. Instead, you prepare (or schedule) a Deep Copy by storing all pertinent information in the recipient object (which most of the time boils down to a mere Shallow Copy) and wait till it becomes known whether the Deep Copy is really necessary for that specific object. If it turns out to be necessary, you perform the actual Deep Copy. If the need for Deep Copy never arises, then it doesn't happen, thus saving you the effort.


Let me speak about C++

One of the very important part writing class in C++ is to implement copy constructor and overloaded = operator function.

This tutorial talks about the need of writing these functions in order to make your program more effective. Before getting into the concept lets understand basic terminology.

Constructor : Its a special function called when object of class is created. Ideally a constructor must contain the logic to initialize the data members of the class.

Copy Constructor: It is called when and object is initialized at the time of creation. There exist more scenario when an copy constructor is called.

Operator function: C++ allows to overload operator with the help of operator keyword. This helps us to treat user defined types as basic types.

Default copy constructor and =operator function which is inserted by compiler incase they are missing from the class. It performs a bit pattern copy i.e. simply copies data members of one object into another object.

Consider following code sample

    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.

}

In the above example

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.

Similarly statement

 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.

The above code will work as expected until the class member is not allocated any resource (file or memory). Consider a scenario where the class is updated as follow.

     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;
   }
 };
0

精彩评论

暂无评论...
验证码 换一张
取 消