Implement a Thread-Safe Reference-Counted Smart Pointer in C++
Company: NVIDIA
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Onsite
Implement a reference-counted smart pointer class template in C++ from scratch, similar in spirit to `std::shared_ptr`. Several owners may hold the same object; the object must be destroyed exactly once, when the last owner releases it, and never while any owner still uses it. This came up as a "system coding" exercise on an autonomous-driving team that works entirely in C++, so expect questions about resource ownership, copy and move semantics, and thread safety rather than about algorithms.
Provide at least this interface:
```cpp
template <typename T>
class SharedPtr {
public:
SharedPtr() noexcept; // empty, owns nothing
explicit SharedPtr(T* p); // takes ownership of p (allocated with new)
SharedPtr(const SharedPtr& other); // shares ownership
SharedPtr(SharedPtr&& other) noexcept; // transfers ownership, leaves other empty
SharedPtr& operator=(const SharedPtr& other);
SharedPtr& operator=(SharedPtr&& other) noexcept;
~SharedPtr();
void reset(T* p = nullptr); // release current object, optionally own p
T* get() const noexcept;
T& operator*() const;
T* operator->() const noexcept;
explicit operator bool() const noexcept;
std::size_t use_count() const noexcept; // number of owners; 0 when empty
};
```
```hint Where the count lives
Decide where the count must be stored so that every copy sees the same value, and who is responsible for freeing that storage.
```
```hint Trace an assignment
Walk through `a = b` when `a` and `b` own different objects, and again when they are the same object, counting every increment, decrement and deletion.
```
### Constraints
- C++17 or later. Do not use `std::shared_ptr`, `std::unique_ptr` or `std::weak_ptr`.
- The pointer owns single objects allocated with `new`, not arrays.
- An empty `SharedPtr`, including one constructed from a null pointer, reports `use_count() == 0`.
### Clarifying Questions
- Will copies of the same `SharedPtr` be created and destroyed on different threads at the same time, so that count updates must be thread-safe?
- Must a `SharedPtr` to a derived class convert to a `SharedPtr` to its base class?
- Are custom deleters or array support required?
- Is a separate heap allocation for the count acceptable, or should the count live inside the managed object?
- Is a non-owning "weak" reference needed?
### What a Strong Answer Covers
- Where the shared count lives and who owns and frees it
- Correct copy and move construction and assignment, including self-assignment and release of the previously held object
- Exception safety: no leak if allocating the count fails
- Thread-safe count updates with a justified memory ordering, and a clear statement of what is still not thread-safe
- Tests that prove each object is destroyed exactly once, including under concurrent copying
### Follow-up Questions
- Add a weak pointer. What must the shared bookkeeping hold now, and when is it freed?
- A `SharedPtr` to a base class is created from a pointer to a derived object, and the base class has no virtual destructor. What happens at the last release, and how can a smart pointer make this safe anyway?
- How would a factory function put the object and its count in a single allocation, and what does that cost once weak pointers exist?
- Two objects hold `SharedPtr`s to each other. What happens when all outside owners go away, and how do you fix it?
Overview: Implement a reference-counted smart pointer class template in C++ from scratch, with copy and move construction and assignment, reset, dereferencing and a use count. It tests ownership rules, self-assignment and exception safety, atomic reference counting with correct memory ordering, and extensions such as weak pointers, base-class conversion and reference cycles.