将make_shared<Base>、继承和强制转换返回到派生未按预期工作?



考虑这个例子,用各种方式构造shared_ptr<T>并返回:

#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,然后依靠隐式强制转换返回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(...)),是否有任何例外情况意味着它不被推荐?

我不熟悉make_shared<T>给带来了什么

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

在这些shared_ptr中没有Derived,因此不能将dynamic_pointer_cast转换为该类型。

然而,它的执行或行为方式似乎与用std::shared_ptr<T>(new T(...))替换时不同

为什么推荐make_shared<T>而不是std::shared_ptr<T>(new T(...))

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

最新更新