[OOP] Shallow copy và deep copy trong C++

Shallow copy

Trong bài toán tử gán và hàm tạo sao chép (copy constructor) ta đã biết trong C++ sẽ cung cấp cho class hàm tạo sao chép và hàm toán tử gán mặc định để copy (shallow copy) 1 đối tượng sang 1 đối tượng khác.

Mọi thứ sẽ bình thường nếu class không chứa bất kỳ biến con trỏ nào được cấp phát bộ nhớ động.

Ví dụ:


#include <iostream>

using namespace std;

class PS

{

private:

   int tu;

   int mau;

public:

   PS() : PS(0,0)

   {
      //TODO
   }

   PS(int tu, int mau)

   {

      this->tu = tu;

      this->mau = mau;

   }

   void setValue(int tu, int mau)

   {

      this->tu = tu;

      this->mau = mau;

   }

   friend ostream& operator<<(ostream& out, PS& ps)

   {

      out << ps.tu << "/" << ps.mau;

      return out;

   }

};

int main()

{

   PS ps1(3, 4);

   PS ps2(ps1);

   ps1.setValue(4, 5);

   cout << "PS1 = " << ps1 << endl;

   cout << "PS2 = " << ps2 << endl;

   return 0;

}

Kết quả:

PS1 = 4/5
PS2 = 3/4

Trong ví dụ trên khi đối tượng ps1 thay đổi giá trị thì đối tượng ps2 không bị thay đổi theo.

Tuy nhiên khi class chứa biến con trỏ được cấp phát bộ nhớ động việc copy sẽ xảy ra vấn đề.

Ví dụ:


#include <iostream>

using namespace std;

class Test

{

private:

   int *data;

public:

   Test(int val)

   {

      data = new int(val);

   }

   ~Test()

   {

      delete data;

   }

   void SetVal(int val)

   {

      *data = val;

   }

   int GetVal()

   {

      return *data;

   }

};

int main()

{

   Test t1(5);

   Test t2(t1);

   t1.SetVal(10);

   cout << "Data t1 = " << t1.GetVal() <<endl;

   cout << "Data t2 = " << t2.GetVal() <<endl;

   return 0;

}

Kết quả:

Data t1 = 10
Data t2 = 10

Trong ví dụ trên class Test chứa con trỏ data được cấp phát bộ nhớ động. Khi ta copy đối tượng t1 cho t2 thì con trỏ data của t2 không được cấp phát bộ nhớ mới mà vẫn trỏ vào địa chỉ mà đã cấp phát trước đó cho data của đối tượng t1.

Vì vậy khi đối tượng t1 thay đổi giá trị tại địa chỉ của biến data trỏ vào thì đối tượng t2 cũng thay đổi theo. Để giải quyết vấn đề này ta tạo 1 deep copy trên thành phần con trỏ được cấp phát bộ nhớ động của class.

Deep copy

Ta sẽ cấp phát bộ nhớ mới cho con trỏ của bản sao và copy giá trị sang.

Để xây dựng 1 deep copy ta phải nạp chồng toán tử ‘=’ và viết lại hàm tạo sao chép (copy constructor).

Ví dụ:


#include <iostream>

using namespace std;

class Test

{

private:

   int *data;

public:

   Test(int val)

   {

      data = new int(val);

   }

   ~Test()

   {

      delete data;

   }

   //Hàm copy constructor
   Test(const Test& t)

   {

      data = new int();

      *data = *t.data;

   }

   //Nạp chồng toán tử =
   Test& operator=(Test& t)

   {

      data = new int();

      *data = *t.data;

      return *this;

   }

   void SetVal(int val)

   {

      *data = val;

   }

   int GetVal()

   {

      return *data;

   }

};

int main()

{

   Test t1(5);

   Test t2(t1);

   t1.SetVal(10);

   cout << "Data t1 = " << t1.GetVal() << endl;

   cout << "Data t2 = " << t2.GetVal() << endl;

   return 0;

}

Kết quả:

Data t1 = 10
Data t2 = 5

Was this article helpful?

Leave A Comment?