Dyzzet|
C++ Data Science Алгоритмы Темы · Блог · YouTube
Полиморфная кухня
6. Умные указатели

В C++11 появились три вида умных (интеллектуальных) указателей: std::unique_ptr, std::shared_ptr и std::weak_ptr. Они избавляют от заботы освобождать память и другие ресурсы (если с ними правильно обращаться).

struct Base
{
    virtual void print() const noexcept
    {
        std::cout << "Base (const)" << std::endl;
    }
 
    virtual void print() noexcept
    {
        std::cout << "Base" << std::endl;
    }
 
    virtual ~Base() = default;
};
struct Derived : Base
{
    virtual void print() const noexcept override
    {
        std::cout << "Derived (const)" << std::endl;
    }
 
    virtual void print() noexcept override
    {
        std::cout << "Derived" << std::endl;
    }
};

unique_ptr

Полиморфное поведение прекрасно работает и с типами, скрытыми за умными указателями. Пример для std::unique_ptr:

auto base{ std::make_unique<Base>() };
base->print();
 
auto derived{ std::make_unique<Derived>() };
derived->print();
Base
Derived

std::shared_ptr

Пример для std::shared_ptr.

auto base{ std::make_shared<Base>() };
base->print();
 
auto derived{ std::make_shared<Derived>() };
derived->print();
Base
Derived

Вариант с std::shared_ptr интересен тем, что для него есть обёртки — преобразования типа.

Преобразование типа
Аналог для std::shared_ptr
static_cast
std::static_pointer_cast (C++11)
dynamic_cast
std::dynamic_pointer_cast (C++11)
const_cast
std::const_pointer_cast (C++11)
reinterpret_cast
std::reinterpret_pointer_cast (C++17)

std::static_pointer_cast

Пример в повышающим приведением.

auto basePtr2Derived{ std::static_pointer_cast<Base>(derived) };
basePtr2Derived->print();
Derived

std::dynamic_pointer_cast

За умным указателем на класс Base скрывается объект класса Derived.

if (auto downcasted{ std::dynamic_pointer_cast<Derived>(basePtr2Derived) }; downcasted)
{
    downcasted->print();
}
Derived

dynamic_cast в зависимости от того, как его вызывают, может возвращать nullptr или выбрасывать исключение std::bad_alloc. std::dynamic_pointer_cast является noexcept-функцией, поэтому в случае неудачи возвращает nullptr.

std::const_pointer_cast

Добавить (или убрать) квалификатор const.

auto constBase{ std::const_pointer_cast<const Base>(base) };
constBase->print();
Base (const)

std::reinterpret_pointer_cast

Как и reinterpret_cast, преобразование std::reinterpret_pointer_cast может быть опасно.

struct Fake
{
    virtual void print() const noexcept;
    //virtual void print() noexcept;
};

Обратите внимание, что в этом примере константная перегрузка функции Fake::print() не определена, а неконстантная версия даже не объявлена.

auto reinterpretedDerived{ std::reinterpret_pointer_cast<Fake>(derived) };
reinterpretedDerived->print();
Derived

Исходный код: smart-pointers.cpp.

12 марта
Зарегистрируйтесь и войдите, чтобы оставлять комментарии и голосовать.

Полиморфная кухня
Наследование и полиморфизм в C++
Таблицы виртуальных функций
Множественное и виртуальное наследование
Приведение dynamic_cast и RTTI
C++11 и C++14
Умные указатели
Также может быть интересным
© MMXI—MMXXIII. RSS. Поддержать сайт
Светлая тема / тёмная тема