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

Что такое умные указатели?

1.6 Junior🔥 261 комментариев
#Умные указатели и управление памятью

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

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

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

# Умные указатели в C++

Умные указатели (smart pointers) — это шаблонные классы, которые обёртывают сырые указатели и автоматизируют управление памятью через RAII паттерн. Это одна из ключевых инноваций Modern C++, избавляющая от необходимости вручную вызывать delete.

Основные типы

std::unique_ptr

Уникальный указатель с эксклюзивным владением ресурсом:

std::unique_ptr<MyClass> ptr1(new MyClass());
std::unique_ptr<MyClass> ptr2 = std::move(ptr1);
// ptr1 теперь nullptr, ptr2 владеет объектом
// При выходе ptr2 из области видимости объект удаляется

Особенности:

  • Нулевые накладные расходы (zero-overhead abstraction)
  • Не может быть скопирован (только перемещён)
  • Идеален для исключительного владения
  • Размер = размер указателя (обычно 8 байт)

std::shared_ptr

Разделённое владение ресурсом через подсчёт ссылок (reference counting):

std::shared_ptr<MyClass> ptr1(new MyClass());
std::shared_ptr<MyClass> ptr2 = ptr1;  // копируем
// use_count() вернёт 2
// Объект удалится только когда последний shared_ptr выйдет из области видимости

Особенности:

  • Можно копировать
  • Потокобезопасное изменение счётчика (atomic operations)
  • Требует дополнительную память на управляющий блок (control block)
  • Размер = 2 указателя (16 байт)

Лучшие практики

Когда использовать unique_ptr

  • Функция владеет объектом и несет ответственность за его жизненный цикл
  • Контейнеры с единственным владельцем
  • Вывод: ищите unique_ptr в сигнатурах функций как знак ответственности
std::unique_ptr<DataBuffer> readFileData(const std::string& filename) {
    auto buffer = std::make_unique<DataBuffer>();
    // заполняем buffer
    return buffer;  // move semantics автоматически
}

Когда использовать shared_ptr

  • Граф объектов с множественным владением (например, в играх или GUI)
  • Callback'и с длительным жизненным циклом
  • Аккуратно используй в многопоточных системах
class Observer {
    std::shared_ptr<DataSource> source;
public:
    Observer(std::shared_ptr<DataSource> src) : source(src) {}
};

Хитрости и ошибки

Циклические ссылки

Опасная ситуация с shared_ptr:

struct A { std::shared_ptr<B> b; };
struct B { std::shared_ptr<A> a; };  // утечка памяти!

// Решение: используй std::weak_ptr для обратных ссылок
struct B { std::weak_ptr<A> a; };  // не увеличивает счётчик

make_unique и make_shared

Всегда предпочитай конструкторам new:

// Хорошо: одна выделение памяти
auto ptr = std::make_unique<MyClass>(arg1, arg2);

// Менее эффективно: два выделения
std::unique_ptr<MyClass> ptr(new MyClass(arg1, arg2));

Производительность

  • unique_ptr: нулевые накладные расходы
  • shared_ptr: атомарные операции (дорого в tight loops)
  • В критичных местах предпочитай unique_ptr или stack allocation

Умные указатели — это инструмент для безопасного и эффективного C++ кода.

Что такое умные указатели? | PrepBro