从存储派生类的基类向量中实例化指向派生类的unique_ptr

3

Consider following piece of code:

struct  Fruit
{
   Fruit() {}
   virtual ~Fruit() {}       
   std::string name;
};

struct Banana : public Fruit
{
   std::string color;
};

struct Pineapple : public Fruit
{
   int weight;
};

这是我的主函数:

int main()
{
    std::vector<std::unique_ptr<Fruit>> product;
    product.push_back(std::unique_ptr<Banana>(new Banana)); //product[0] is a Banana
    product.emplace_back(new Pineapple);

    // I need to acess the "color" member of product[0]
    std::unique_ptr<Banana> b = std::move(product[0]); // this doesn't work, why?
    auto c = b->color;
}

product[0]中,我存储了一个指向Banana的unique_ptr,为什么不能将它分配给一个banana unique_ptr?


2
编译器不知道 product[0] 指向的是 Banana 而不是其他 Fruit。如果你确定它指向 Banana,你可以通过强制类型转换告诉编译器。例如:std::unique_ptr<Banana> b{static_cast<Banana*>(product[0].release())}; - Igor Tandetnik
使用release()后,我的product[0]丢失了。我不希望这种情况发生,因为我计划再次使用它。是否有其他方法? - Gaetan
如果编译通过,std::unique_ptr<Banana> b = std::move(product[0]); 也会出现类似的问题,因此我认为这就是你想要的。如果你不想从向量中取得所有权,请使用 auto b = static_cast<Banana*>(product[0].get()); - Igor Tandetnik
2个回答

2

您不想进行所有权转移,因此只需转换指针:

auto& banana = dynamic_cast<Banana&>(*product[0]);
auto c = banana.color;

如果你确信Fruit是一个Banana,那么dynamic_cast可以被static_cast替换掉。 但如果你错了,使用static_cast将导致UB,而使用dynamic_cast可以检查有效性(转换为引用时会抛出异常,转换为指针时会得到空指针)。

1

你需要进行显式转换,因为第一个产品可以是任何水果...编译器无法确定这个水果是香蕉还是菠萝。

正如@IgorTandetnik所说,你可以这样做:

std::unique_ptr<Banana> b{static_cast<Banana*>(product[0].release())};

在使用release()时,还需要使用static_cast

演示实例

注意:不能将b回退到使用auto,因为编译器会选择struct Fruit作为类型,以准备任何子类。


使用 release() 后,我的 product[0] 就永远丢失了。我不希望这种情况发生,因为我计划再次使用它。还有其他方法吗? - Gaetan
1
@Gaetan,一个对象只应该有一个指向它的unique_ptr。如果它是一个本地的std::unique_ptr<Banana> b,那么它不能成为product中的std::unique_ptr<Fruit>元素。也许你只想要一个Banana * b - Caleth
哦,是的,使用Banana* b一切都工作正常。谢谢。因此,unique_ptr不能使用现有的unique_ptr实例化,除非将该现有实例设置为nullptr,对吗? - Gaetan
@Gaetan unique_ptr独特的,即它不能共享所有权。这就是为什么例如无法复制它的原因,所以是的。 - gsamaras

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接