Implement a Thread-Safe Reference-Counted Smart Pointer in C++

Quick 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.

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.

|Home/Software Engineering Fundamentals/NVIDIA
NVIDIA logo
NVIDIA
Sep 15, 2026
mediumSoftware EngineerOnsiteSoftware Engineering Fundamentals
0
0

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_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 Guidance

  • 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 Guidance

  • 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 Guidance

  • 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?
Loading comments...