Implement a Thread-Safe Reference-Counted Smart Pointer in C++
NVIDIASoftware Engineer · OnsiteLast updated
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.
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:
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
};
Constraints
- C++17 or later. Do not use
std::shared_ptr,std::unique_ptrorstd::weak_ptr. - The pointer owns single objects allocated with
new, not arrays. - An empty
SharedPtr, including one constructed from a null pointer, reportsuse_count() == 0.
Clarifying Questions
- Will copies of the same
SharedPtrbe created and destroyed on different threads at the same time, so that count updates must be thread-safe? - Must a
SharedPtrto a derived class convert to aSharedPtrto 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?
Hints
Hint 1
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 2
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.
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?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.