Problem Statement
Implement a simplified version of C++'s shared_ptr that supports:
- Reference counting — track how many
shared_ptrinstances point to the same object - Automatic deletion — delete the managed object when the last
shared_ptrgoes out of scope - Copy semantics — copying a
shared_ptrincrements the reference count - Assignment — handle self-assignment, decrement old count, increment new count
- Destructor — decrement count, delete if zero
Constraints
- Must handle copy constructor, copy assignment, and destructor correctly
- Must not leak memory or double-free
- Thread safety is NOT required (bonus if discussed)
- Template-based to support any type
Expected Interface
template <typename T>
class SharedPtr {
public:
SharedPtr(T* ptr = nullptr);
SharedPtr(const SharedPtr& other); // copy constructor
SharedPtr& operator=(const SharedPtr& other); // copy assignment
~SharedPtr();
T& operator*() const;
T* operator->() const;
int use_count() const;
};
Example
SharedPtr<int> p1(new int(42)); // count = 1
SharedPtr<int> p2 = p1; // count = 2
SharedPtr<int> p3;
p3 = p2; // count = 3
// p1 goes out of scope → count = 2
// p2 goes out of scope → count = 1
// p3 goes out of scope → count = 0, memory freed
What the Interviewer Expects
- Separate control block — the reference count lives on the heap, shared between all copies
- Copy constructor — copy the pointer AND the count pointer, then increment
- Assignment operator — decrement old, increment new, handle self-assignment
- Destructor — decrement, if zero delete both the object and the control block
- Bonus: Discuss how
weak_ptrbreaks circular references
Follow-ups
- How would you add
weak_ptrsupport? What changes in the control block? - How would you make this thread-safe? (atomic reference count)
- What's the difference between
shared_ptr<T>(new T)andmake_shared<T>()? Why does it matter? - How would you implement custom deleters?
- Can you demonstrate a memory leak even with
shared_ptr? (circular reference)