Умный указатель в C++ | OTUS
⚡ Подписка на курсы OTUS!
Интенсивная прокачка навыков для IT-специалистов!
Подробнее

Курсы

Программирование
Backend-разработчик на PHP Алгоритмы и структуры данных Team Lead Архитектура и шаблоны проектирования Разработчик IoT C# Developer. Professional HTML/CSS
-11%
C# ASP.NET Core разработчик
-5%
Kotlin Backend Developer
-8%
iOS Developer. Professional
-8%
Symfony Framework Unity Game Developer. Basic JavaScript Developer. Professional Android Developer. Basic JavaScript Developer. Basic Java Developer. Professional Highload Architect Reverse-Engineering. Professional Java Developer. Basic Web-разработчик на Python Framework Laravel Cloud Solution Architecture Vue.js разработчик Интенсив «Оптимизация в Java» Супер - интенсив по паттернам проектирования Супер - интенсив по Kubernetes Супер-интенсив "Tarantool" PHP Developer. Basic
Инфраструктура
Мониторинг и логирование: Zabbix, Prometheus, ELK Administrator Linux. Professional Дизайн сетей ЦОД Разработчик IoT PostgreSQL Экспресс-курс "Версионирование и командная работа с помощью Git"
-30%
Microservice Architecture Highload Architect MS SQL Server Developer Разработчик программных роботов (RPA) на базе UiPath и PIX Разработчик голосовых ассистентов и чат-ботов Administrator Linux. Advanced Infrastructure as a code Супер-практикум по использованию и настройке GIT Administrator Linux.Basic Экспресс-курс «IaC Ansible» Экспресс-курс «CI/CD или Непрерывная поставка с Docker и Kubernetes» Основы Windows Server
Корпоративные курсы
Безопасность веб-приложений IT-Recruiter Дизайн сетей ЦОД Компьютерное зрение Разработчик IoT Вебинар CERTIPORT Machine Learning. Professional
-6%
NoSQL Пентест. Практика тестирования на проникновение Java QA Engineer. Базовый курс Руководитель поддержки пользователей в IT
-8%
SRE практики и инструменты Cloud Solution Architecture Внедрение и работа в DevSecOps Супер-практикум по работе с протоколом BGP Infrastructure as a code Супер-практикум по использованию и настройке GIT Промышленный ML на больших данных Экспресс-курс «CI/CD или Непрерывная поставка с Docker и Kubernetes» BPMN: Моделирование бизнес-процессов Основы Windows Server
Специализации Курсы в разработке Подготовительные курсы Подписка
+7 499 938-92-02

Умный указатель в C++

Cplus_Deep_13.1-5020-d3bffc.png

Умный указатель в C++ (его ещё называют интеллектуальным) обеспечивает безопасность за счёт автоматического управления памятью. Такое решение позволит избежать ряда проблем при написании кода (отказов в выделении памяти, «утечек» памяти и пр.)

Умный указатель (Smart pointer) должен подсчитывать число ссылок на указанный объект. Поначалу может показаться, что это довольно сложная задача, особенно если вы не являетесь экспертом в C++. Давайте попробуем решить её, разделив на 2 части: 1) обрисуем общий подход и создадим псевдокод; 2) напишем подробный код.

Нам потребуется переменная — счётчик ссылок. Переменная будет увеличиваться, если мы будем добавлять новую ссылку на объект, и уменьшаться, если будем удалять ссылку.

Пример псевдокода:

template 
class SmartPointer {
    /* Класс Smart-указателя нуждается в указателях на самого
     * себя и на счётчик ссылок. Оба они должны быть указателями, а не реальным
     * объектом или значением счётчика ссылок, ведь цель умного
     * указателя — подсчитать число ссылок через множество 
     * Smart-указателей на один объект */
    T * obj;
    unsigned * ref_count;
}

Для данного класса нам потребуются деструктор и конструктор, давайте опишем их:

SmartPointer(T * object) {
    /* Мы желаем установить значение T * obj и установить счетчик
     * ссылок в 1. */
}

SmartPointer(SmartPointer & sptr) {
    /* Данный конструктор создает новый умный указатель на существующий
     * объект. Нам нужно сначала установить obj и ref_count
     * такими же, как в sptr. Потом, 
     * т. к. мы создали новую ссылку на obj, нужно
     * увеличить ref_count. */
}

~SmartPointer(SmartPointer sptr) {
    /* Уничтожаем ссылку на объект. Уменьшаем
     * ref_count. Если ref_count = 0, то освобождаем память и
     * уничтожаем объект. */
}

Есть и дополнительный способ создания ссылок — установить один SmartPointer в другой. Для этого потребуется переопределить оператор, но давайте сначала сделаем набросок кода:

onSetEqals(SmartPointer ptr1, SmartPointer ptr2) {
    /* Если ptr1 имеет существующее значение, уменьшаем его число ссылок.
    * Потом копируем указатели obj и  ref_count. В результате,
    * поскольку мы создали новую ссылку, нужно увеличить
    * ref_count. */
}

Что же, теперь осталось лишь написать итоговый код:

template 
class SmartPointer {
public:
    SmartPointer(T * ptr) {
        ref = ptr;
        ref_count = (unsigned*)malloc(sizeof(unsigned));
        *ref_count = 1;
    }

    SmartPointer(SmartPointer & sptr) {
        ref = sptr.ref;
        ref_count = sptr.ref_count;
        ++(*ref_count);
    }

    /* Перезаписываем оператор равенства (eqal), поэтому, когда вы установите
     * один умный указатель в другой, число ссылок старого указателя
     * уменьшится, а нового — увеличится. 
     */
    SmartPointer & operator=(SmartPointer & sptr) {
        /* Если уже присвоено объекту, удаляем одну ссылку. */
        if (*ref_count > 0) {
            remove();
        }
        if (this != &sptr) {
            ref = sptr.ref;
            ref_count = sptr.ref_count;
            ++(*ref_count);
        }
        return *this;
    }

    ~SmartPointer() {
        remove(); // удаляем одну ссылку на объект.
    }

    T operator*() {
        return *ref;
    }

    protected:
    void remove() {
        --(*ref_count);
        if (ref_count == 0) {
            delete ref;
            free(ref_count);
            ref = NULL;
            ref_count = NULL;
        }
    }

    T * ref;
    unsigned * ref_count;
}

Вот и всё, ждём ваших комментариев!

Статья написана на основе одного из заданий книги «Карьера программиста. Как устроиться на работу в Google, Microsoft или другую ведущую IT-компанию», Лакман Г.

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться