Нужен общий управляющий блок с объектом и числом владельцев. Copy увеличивает число, move переносит указатель на блок, а последний destructor освобождает ресурс. Все операции должны поддерживать пустое состояние.
Создание собственного аналога std::shared_ptr
Нужен общий управляющий блок с объектом и числом владельцев. 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, требует отдельной фабрики; получить её простым принятием готового сырого указателя нельзя.