Skip to content
UniCircle
MediumConceptualObject lifecycle

Shallow copy vs deep copy in C++ (and the rule of three)

Question OOP-108

Explain the difference between a shallow copy and a deep copy of an object. Show a bug that shallow copying causes in C++, and explain the "rule of three". How does copying behave by default in Java and Python?

Show hints

Focus on what happens to members that are pointers or references.

Show the explanation

Model answer.

  • Shallow copy: copies each field's value as-is. For fields that are pointers or references, only the address is copied, so the original and the copy share the same underlying object.
  • Deep copy: also duplicates the objects that those pointers or references refer to (recursively, as far as needed), so the copy is fully independent.

C++ bug with the default (shallow) copy

C++
class Buffer {
    int* data; size_t n;
public:
    Buffer(size_t n) : data(new int[n]), n(n) {}
    ~Buffer() { delete[] data; }
};
Buffer a(10);
Buffer b = a;   // compiler-generated copy: b.data == a.data

When b and a go out of scope, both destructors call delete[] on the same pointer — a double free, which is undefined behaviour. Writing through b.data would also silently change a.

Rule of three: if a class needs a user-defined destructor, copy constructor or copy assignment operator, it almost certainly needs all three, because it manages a resource. The copy constructor and assignment should allocate new memory and copy the contents. In C++11 and later this extends to the rule of five (add move constructor and move assignment). The modern preference is the rule of zero: hold resources in RAII types such as std::vector or std::unique_ptr so the compiler-generated members are already correct.

Java

  • Assignment b = a copies the reference only — no new object at all.
  • Object.clone() (for classes implementing Cloneable) produces a field-by-field shallow copy; arrays or lists inside must be cloned manually for a deep copy. Many developers prefer copy constructors or factory methods instead.

Python

  • b = a binds another name to the same object.
  • copy.copy(a) is shallow; copy.deepcopy(a) is deep. For a list of lists, copy.copy shares the inner lists.

Common follow-up: "Is shallow copy ever the right choice?" Yes — when the shared parts are immutable (e.g. Java Strings) shallow copying is safe and cheaper.

Original UniCircle question. Last reviewed 28 Oct 2026.