← Назад к вопросам

Какую проблему решает std::weak_ptr?

2.0 Middle🔥 181 комментариев
#Умные указатели и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение: std::weak_ptr и циклические ссылки

std::weak_ptr решает критическую проблему циклических зависимостей в графе объектов, управляемых через std::shared_ptr. Без него программы страдают от утечек памяти и зависающих деструкторов.

Суть проблемы

Когда два объекта ссылаются друг на друга через shared_ptr, образуется цикл:

struct Node {
    std::shared_ptr<Node> next;
};

auto a = std::make_shared<Node>();
auto b = std::make_shared<Node>();

a->next = b;  // refcount(b) = 2
b->next = a;  // refcount(a) = 2

// Выходим из скоупа
// a destructor вызовет delete, но next указывает на b
// b destructor не может быть вызван, т.к. a->next = b
// УТЕЧКА ПАМЯТИ!

Refcount никогда не достигает нуля, объекты остаются в памяти навсегда.

Как weak_ptr решает проблему

weak_ptr — это не владеющий указатель. Он может ссылаться на объект, но НЕ увеличивает refcount:

struct Node {
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> prev;  // <-- не владеет!
};

auto a = std::make_shared<Node>();
auto b = std::make_shared<Node>();

a->next = b;           // refcount(b) = 2
b->prev = a;           // refcount(a) = 1 (не увеличилась!)

// Выходим из скоупа
// refcount(a) = 0 -> destructor вызван
// refcount(b) = 1 -> но a->next удалена
// refcount(b) = 0 -> destructor вызван
// ВСЁ ХОРОШО

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

Перед использованием weak_ptr нужно превратить его обратно в shared_ptr через lock():

if (auto ptr = weak_ptr.lock()) {
    // Безопасно работаем с ptr
    ptr->doSomething();
}
// lock() вернула nullptr, если объект уже удален

Практические сценарии

Паттерн Observer:

class Subject {
    std::vector<std::weak_ptr<Observer>> observers;
};

Граф объектов с обратными ссылками:

struct TreeNode {
    std::shared_ptr<TreeNode> left, right;
    std::weak_ptr<TreeNode> parent;  // Обратная ссылка
};

Кэширование:

std::unordered_map<int, std::weak_ptr<Resource>> cache;
// Объект может быть удален, кэш автоматически станет невалидным

Ключевые особенности

  • Не владеет памятью — не влияет на жизненный цикл
  • Требует lock() перед использованием
  • Автоматическая инвалидация — lock() вернёт nullptr если объект удалён
  • Используется в parent/observer паттернах — для иерархических структур
  • Нулевой оверхед — lock() очень быстрая операция

std::weak_ptr — это необходимый инструмент для корректного управления памятью в сложных графах объектов с циклическими зависимостями.

Какую проблему решает std::weak_ptr? | PrepBro