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 — локальная установка не требуется.
Все уроки этого курса
- Почему умные указатели заменяют обычные new и delete
- unique_ptr: исключительное владение
- shared_ptr и weak_ptr: совместное владение
- Пользовательские удалители и функции make