0Pricing
C++ Academy · Урок

shared_ptr и weak_ptr: совместное владение

Разделяйте владение с помощью подсчёта ссылок и разрывайте циклы с помощью weak_ptr.

«shared_ptr и weak_ptr: совместное владение» — бесплатный урок C++ Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.

Совместное владение объектом

Иногда нескольким частям программы нужно сохранять объект живым. std::shared_ptr<T> обеспечивает совместное владение с подсчётом ссылок.

Создание shared_ptr

Используйте std::make_shared — он выделяет блок управления и объект одним выделением памяти.

#include <memory>
auto s = std::make_shared<Widget>(42);
std::cout << s.use_count();   // 1

Копирование разделяет владение

Копирование shared_ptr увеличивает счётчик ссылок. Уничтожение или переназначение уменьшает его. Когда счётчик достигает нуля, объект удаляется.

auto a = std::make_shared<Widget>();
auto b = a;                  // ref count is now 2
std::cout << a.use_count();  // 2

Как это работает внутри

shared_ptr хранит два указателя: один на объект, другой на блок управления, содержащий счётчик или счётчики ссылок. Блок управления выделяется в куче.

Атомарный счётчик ссылок

Счётчик ссылок использует атомарные операции, поэтому shared_ptr можно безопасно копировать между потоками. Однако сам объект, на который указывает указатель, автоматически потокобезопасным не становится.

Сброс и переназначение

Присваивание нового значения уменьшает старый счётчик ссылок и увеличивает новый. reset() устанавливает shared_ptr в пустое состояние.

Создание shared_ptr из необработанного указателя (избегайте этого)

Не создавайте два shared_ptr из одного необработанного указателя — у каждого будет собственный управляющий блок. Всегда используйте make_shared.

// BUG
Widget* raw = new Widget();
std::shared_ptr<Widget> a(raw);
std::shared_ptr<Widget> b(raw);   // disaster: two control blocks

Проблема циклических ссылок

Два shared_ptr, ссылающиеся друг на друга, образуют цикл — ни у одного счётчик ссылок не достигает нуля, и ни один объект не освобождается. Происходит утечка памяти.

struct Node {
    std::shared_ptr<Node> next;
};
auto a = std::make_shared<Node>();
auto b = std::make_shared<Node>();
a->next = b;
b->next = a;     // cycle — never freed

Разрыв циклов с помощью weak_ptr

std::weak_ptr<T> наблюдает за shared_ptr, не участвуя в подсчёте ссылок. Сделайте одну сторону связи слабой, чтобы разорвать цикл.

struct Node {
    std::shared_ptr<Node> next;
    std::weak_ptr<Node>  prev;     // weak — does not own
};

Использование weak_ptr

Нельзя напрямую разыменовать weak_ptr. Вызовите lock(), чтобы получить shared_ptr (или пустой указатель, если объект уже уничтожен).

std::weak_ptr<Widget> w = sharedPtr;
if (auto p = w.lock()) {
    p->use();   // safe — we have a shared_ptr now
} else {
    std::cout << "object expired";
}

Цена по сравнению с unique_ptr

shared_ptr занимает больше места (два указателя и управляющий блок) и работает медленнее (из-за атомарного счётчика ссылок). Используйте его только тогда, когда владение действительно должно быть совместным.

Быстрая проверка

Каков типичный вариант использования std::weak_ptr?

Итоги

shared_ptr отслеживает владение с помощью атомарного счётчика ссылок. Используйте make_shared, остерегайтесь циклов и разрывайте их с помощью weak_ptr. Если совместное владение не требуется, предпочитайте unique_ptr.

Часто задаваемые вопросы

Урок «shared_ptr и weak_ptr: совместное владение» бесплатный?

Да — полный текст урока «shared_ptr и weak_ptr: совместное владение» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.

Чему я научусь в уроке «shared_ptr и weak_ptr: совместное владение»?

Разделяйте владение с помощью подсчёта ссылок и разрывайте циклы с помощью weak_ptr. Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C++ Academy?

Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «shared_ptr и weak_ptr: совместное владение»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C++ Academy?

Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Почему умные указатели заменяют обычные new и delete
  2. unique_ptr: исключительное владение
  3. shared_ptr и weak_ptr: совместное владение
  4. Пользовательские удалители и функции make
← Назад к C++ Academy