"Cloning" in the coding world: deep copy vs. shallow copy

2024.02.06

Deep copy and shallow copy, as two different copy methods, directly affect the correctness and performance of the program.

1. What is copy?

In C++ programming, copying is the process of copying the value of one object to another object. This seemingly simple operation involves two different implementation methods: deep copy and shallow copy. Let's start with a shallow copy and see how it works.

2. Shallow copy: superficial copy

Shallow copy is a simple copy method that only copies the value of the object, including the basic data types and pointers in the object. In a shallow copy, both objects share the same memory space, which can lead to potential problems, especially when the objects contain dynamically allocated memory.


// 示例:浅拷贝
#include <iostream>
class ShallowCopyExample {
public:
    int* data;
    ShallowCopyExample(const ShallowCopyExample& other) {
        // 浅拷贝
        data = other.data;
    }
    void DisplayData() {
        std::cout << "Data: " << *data << std::endl;
    }
};

int main() {
    ShallowCopyExample obj1;
    obj1.data = new int(42);
    ShallowCopyExample obj2 = obj1; // 浅拷贝
    obj1.DisplayData(); // 输出:Data: 42
    obj2.DisplayData(); // 输出:Data: 42
    // 修改obj1的data
    *obj1.data = 99;
    obj1.DisplayData(); // 输出:Data: 99
    obj2.DisplayData(); // 输出:Data: 99,这里也发生了变化!
    // 注意:由于浅拷贝,obj1和obj2共享相同的data指针,导致一个变化另一个也跟着变化
    delete obj1.data;
    // 注意:由于浅拷贝,删除obj1的data后,obj2的data指针成为了悬空指针,可能导致未定义行为
    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

In this example, two objects obj1 and obj2 share the same data pointer through shallow copy. Modifying the data of one object will affect the other object, and you need to be extra careful when releasing memory to avoid the problem of dangling pointers.

3. Deep Copy: Integrity of Replication

Compared with shallow copy, deep copy copies all the contents of the object, including the memory pointed to by the pointer. In this way, each object has its own independent copy of the data and does not affect each other.


// 示例:深拷贝
#include <iostream>
class DeepCopyExample {
public:
    int* data;
    DeepCopyExample(const DeepCopyExample& other) {
        // 深拷贝
        data = new int(*other.data);
    }
    ~DeepCopyExample() {
        // 注意:需要手动释放动态分配的内存
        delete data;
    }
    void DisplayData() {
        std::cout << "Data: " << *data << std::endl;
    }
};
int main() {
    DeepCopyExample obj1;
    obj1.data = new int(42);
    DeepCopyExample obj2 = obj1; // 深拷贝
    obj1.DisplayData(); // 输出:Data: 42
    obj2.DisplayData(); // 输出:Data: 42
    // 修改obj1的data
    *obj1.data = 99;
    obj1.DisplayData(); // 输出:Data: 99
    obj2.DisplayData(); // 输出:Data: 42,这里没有变化!
    // 注意:由于深拷贝,obj1和obj2拥有独立的data指针,互不影响
    delete obj1.data;
    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.

In the deep copy example, each object has its own data pointer and corresponding memory. This design ensures the independence between objects and prevents problems caused by data sharing.

4. How to choose: deep copy or shallow copy?

Choosing deep copy or shallow copy depends on specific needs and design. In some cases, a shallow copy may be appropriate, especially when the object does not have dynamically allocated memory or when sharing data is the desired behavior. However, if the object contains pointers, or if independence needs to be maintained between different objects, a deep copy is a safer option.

5. Note: Release of dynamically allocated memory

When using deep copies, pay special attention to dynamically allocated memory to ensure proper release at the end of the object's life cycle. In the above deep copy example, we used the destructor to release the memory pointed to by data.

6. Summary: Flexible use of copy methods

Both deep copy and shallow copy have their applicable scenarios in C++. Understanding their principles and usage will help us apply them more flexibly in actual programming. By choosing the appropriate copy method, we can better manage data and ensure program correctness and performance.