Std:: shared_ptr повышение до базового класса - лучший метод?

Какое преобразование лучше, и в чем разница?

class Base
{};

class Derived : public Base, public std::enable_shared_from_this<Derived>
{};

int main(int argc, const char * argv[])
{
    std::shared_ptr<Base> ptr1 = std::dynamic_pointer_cast<Base>(std::shared_ptr<Derived>(new Derived())); // version 1
    std::shared_ptr<Base> ptr2 = std::shared_ptr<Derived>(new Derived()); // version 2
    return 0;
}

Ответы

Ответ 1

Как и в других случаях использования shared_ptr, вы должны использовать make_shared вместо создания shared_ptr вручную:

std::shared_ptr<Base> ptr2 = std::make_shared<Derived>();

Это по существу ваша версия 2, плюс различные преимущества make_shared.

В версии 1 есть куча ненужных вещей: сначала вы создаете временный shared_ptr<Derived>, а затем dynamic_cast его содержимое указателю базового класса (в то время как static_cast здесь будет достаточно), а затем вы сохраняете этот указатель в другом shared_ptr<Base>. Таким образом, у вас много ненужных операций времени выполнения, но нет преимуществ в отношении безопасности типов по сравнению с версией 2.

Ответ 2

Второй имеет смысл, поскольку он является точным транспозированием того, что было бы сделано с помощью реального указателя, избегая при этом использования явного приведения, т.е.

Base* ptr = new Derived();

Другим вариантом будет использование std::make_shared с указанием Derived в качестве параметра шаблона, то есть:

std::shared_ptr<Base> ptr2 = std::make_shared<Derived>();

Ответ 3

Кажется, что самый очевидный ответ не был упомянут, поэтому я добавлю это для полноты.

Вам не нужен листинг, лучший способ выполнить это:

#include <memory>

class Base 
{};

class Derived : public Base, public std::enable_shared_from_this<Derived>
{};

int main(int argc, const char * argv[])
{
     std::shared_ptr<Derived> ptr1 = std::make_shared<Derived>();
     std::shared_ptr<Base> ptr2 = ptr1; // no CAST NEEDED HERE AS YOU SEE :)
     return 0;
}

вытекающий из enable_shared_from_this, ничего не меняет в этом случае. вы могли бы также использовать следующие классы (делая ваш код немного читабельнее)

class Base 
{};

class Derived: public Base
{};

Конечно, я не знаю ваших деталей реализации, поэтому очень возможно, что вам все еще нужно получить от enable_shared_from_this