Для чего нужен
shared_ptr нужен для ситуации, когда имеются несколько ссылок на объект, созданных в динамической памяти. При этом освобождать объект нужно тогда, когда удаляется последняя ссылка. И делать это нужно безопасно даже в многопоточном коде.
Как отслеживать ссылки на объект
Каждый объект shared_ptr содержит созданный в динамической памяти счётчик ссылок, который увеличивается на единицу, когда shared_ptr завладевает объектом, и уменьшается на единицу, когда shared_ptr перестаёт владеть объектом.
Код объекта счётчика ссылок может выглядеть так:
template <typename T> class sp_counted { public: explicit sp_counted(T *p) noexcept : count(1), ptr(p) {} void add_ref() noexcept { ++count; } void release() noexcept { if (!--count) { delete ptr; delete this; } } size_t use_count() const noexcept { return count.load(); } private: std::atomic<size_t> count; T *ptr; };При этом код shared_ptr может выглядеть так:
template <typename T> class shared_ptr { public: shared_ptr() noexcept : ptr(nullptr), counted(nullptr) {} // excaption safe конструктор explicit shared_ptr(T *p) { std::unique_ptr<T> holder(p); // new может кинуть исключение, и, если p не передать в unique_ptr, // память под p потеряется counted = new sp_counted<T>(holder.get()); ptr = holder.release(); } ~shared_ptr() noexcept { release(); } shared_ptr(const shared_ptr &other) noexcept : ptr(other.ptr), counted(other.counted) { add_ref(); } shared_ptr &operator=(const shared_ptr &other) noexcept { // Освобождаем владение предыдущим указателем release(); // Выполняем присваивание ptr = other.ptr; counted = other.counted; // Устанавливаем владение новым указателем add_ref(); // Ура! Я не забыл вернуть *this! return *this; } T *get() const noexcept { return ptr; } size_t use_count() const noexcept { return counted != nullptr ? counted->use_count() : 0; } private: void add_ref() { if (counted) { counted->add_ref(); } } void release() { if (counted) { counted->release(); } } private: T *ptr; sp_counted<T> *counted; };
А что с потокобезопасностью?
Любая операция с shared_ptr потокобезопасна, если каждый поток хранит копию shared_ptr. При этом каждая копия может хранить указатель на один объект.
Хранить ссылки на один shared_ptr в разных потоках непотокобезопасно.
Комментариев нет:
Отправить комментарий