Создание собственного аналога std::shared_ptr

Нужен общий управляющий блок с объектом и числом владельцев. Copy увеличивает число, move переносит указатель на блок, а последний destructor освобождает ресурс. Все операции должны поддерживать пустое состояние.

Короткий ответ

Что ответить на собеседовании

Нужен общий управляющий блок с объектом и числом владельцев. Copy увеличивает число, move переносит указатель на блок, а последний destructor освобождает ресурс. Все операции должны поддерживать пустое состояние.

Подробный разбор

Ответ с пояснениями

Условие

Требуется реализовать собственный вариант умного указателя, схожего с std::shared_ptr, с упором на эффективность. Необходимо реализовать следующие члены:

  • конструктор без параметров
  • конструктор, принимающий сырой указатель
  • конструктор копирования
  • оператор копирования
  • конструктор перемещения
  • оператор перемещения
  • деструктор

Ответ

Нужен общий управляющий блок с объектом и числом владельцев. Copy увеличивает число, move переносит указатель на блок, а последний destructor освобождает ресурс. Все операции должны поддерживать пустое состояние.

Минимальный однопоточный вариант с отдельными copy/move-операциями:

#include <cstddef>
#include <utility>

template<class T>
class SharedPtr {
    struct Control {
        T* value;
        std::size_t refs = 1;
        explicit Control(T* p) : value(p) {}
        ~Control() { delete value; }
    };
    Control* state = nullptr;
    void release() noexcept {
        if (state && --state->refs == 0) delete state;
    }
public:
    SharedPtr() noexcept = default;
    explicit SharedPtr(T* p) {
        if (!p) return;
        try { state = new Control(p); }
        catch (...) { delete p; throw; }
    }
    SharedPtr(const SharedPtr& other) noexcept : state(other.state) {
        if (state) ++state->refs;
    }
    SharedPtr& operator=(const SharedPtr& other) noexcept {
        if (this != &other) {
            Control* next = other.state;
            if (next) ++next->refs;
            release();
            state = next;
        }
        return *this;
    }
    SharedPtr(SharedPtr&& other) noexcept
        : state(std::exchange(other.state, nullptr)) {}
    SharedPtr& operator=(SharedPtr&& other) noexcept {
        if (this != &other) {
            release();
            state = std::exchange(other.state, nullptr);
        }
        return *this;
    }
    ~SharedPtr() { release(); }
    T* get() const noexcept { return state ? state->value : nullptr; }
};

Копирование и перемещение выполняются за O(1). Пример рассчитан на одиночный объект с не бросающим деструктором и не реализует weak_ptr, массивы, пользовательские deleter или многопоточный счётчик. Оптимизация совместного выделения объекта и блока, как в make_shared, требует отдельной фабрики; получить её простым принятием готового сырого указателя нельзя.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее