返回 make_shared<Base>、继承和转换为 Derived 未按预期工作?

Returning make_shared<Base>, inheritence and casting to Derived not working as expected?

考虑以各种方式构建 shared_ptr<T> 的示例,然后 returning:

#include <memory>
#include <iostream>

class Base
{
public:
    virtual ~Base() {}
    Base(int y) : y_(y) {}
    int y_;
};

class Derived : public Base
{
public:
    Derived(int y, int z) : Base(y), z_(z) {}
    int z_;
};

std::shared_ptr<Base> A()
{
    return std::shared_ptr<Base>(new Derived(1, 2));
}

std::shared_ptr<Base> B()
{
    std::shared_ptr<Derived> result = std::make_shared<Derived>(Derived(1, 2));
    return result;
}

std::shared_ptr<Base> C()
{
    std::shared_ptr<Base> result = std::make_shared<Base>(Derived(1, 2));
    return result;
}

std::shared_ptr<Base> D()
{
    return std::make_shared<Base>(Derived(1, 2));
}


int main(int argc, char** argv)
{
    // Works fine...
    std::shared_ptr<Derived> resultA = std::dynamic_pointer_cast<Derived>(A());
    
    // Works fine...
    std::shared_ptr<Derived> resultB = std::dynamic_pointer_cast<Derived>(B());
    
    // Does not cast to base? ...
    std::shared_ptr<Derived> resultC = std::dynamic_pointer_cast<Derived>(C());

    // Object returns fine (of type Base), but cannot be cast to Derived?
    std::shared_ptr<Base> resultCBase = C();
    std::shared_ptr<Derived> resultCDerived = std::dynamic_pointer_cast<Derived>(resultCBase);
    
    // Does not cast to derived...
    std::shared_ptr<Derived> resultD = std::dynamic_pointer_cast<Derived>(D());

    return 0;
}

总结:

返回 std::make_shared<T> 似乎工作正常并允许调用者正确转换。 (参见 A())。

使用 make_shared<Derived> 创建 Derived,然后依靠隐式转换为 return 和 shared_ptr<Base> 工作并允许调用者正确转换。 (参见 B())。

然而,对于 C()D(),当使用 make_shared<Base>(Derived(...)) 时,shared_ptr<Base> 被构造(似乎正确)但不能转换为 std::shared_ptr<Derived>?

我不熟悉 make_shared<T> 给出的内容(尽管 SO 的其他答案提到了更好的类型安全性和单一分配?),但它的执行或行为方式似乎与替换为 std::shared_ptr<T>(new T(...))?

有人可以向我解释这里发生了什么以及为什么它没有像我预期的那样工作(我想我使用它是错误的,或者在使用它时我应该知道一些微妙的行为特征)?

由于上面的示例存在差异,A() & B() 有效,但 C()D() 无效(假设我使用正确)...为什么make_shared<T> 是否比 std::shared_ptr<T>(new T(...)) 更推荐,是否有任何例外情况意味着不推荐它?

I'm not familiar with what make_shared<T> gives

它创建一个 T(在堆上,将其包装在 shared_ptr 中)。它只创建 T。您的 make_shared<Base> 调用相当于 new Base(Derived(1, 2)。这将构造一个 Base(通过从给定的 DerivedBase 子对象复制,通常称为“切片”,因为您只是复制对象的一部分),因为那是你给的类型。

那些 shared_ptr 中没有 Derived,所以你不能 dynamic_pointer_cast 那个类型。

however it doesn't seem to perform or behave in the same manner as when replacing with std::shared_ptr<T>(new T(...))

why is make_shared<T> recommended over std::shared_ptr<T>(new T(...)),

std::shared_ptr<Base>(new Base(Derived(1, 2))) 会遇到完全相同的问题。这与 make_shared 无关,与您创建错误类型有关。