首页 > 解决方案 > 使用模板向上转换 unique_ptr

问题描述

考虑以下简单代码:

#include <memory>

template<typename T>
struct Foo
{
    virtual T & foo() = 0;
};

struct Bar : public Foo<int>
{
    int x;
    virtual int & foo() override
    {
        return x;
    }
};

void baz(std::unique_ptr<Foo<int>>)
{
}

int main()
{
    auto up = std::make_unique<Bar>();
    baz(up);
    return 0;
}

它不会编译报告此错误:

prog.cc:27:9: error: could not convert 'up' from 'unique_ptr<Bar,default_delete<Bar>>' to 'unique_ptr<Foo<int>,default_delete<Foo<int>>>'
   27 |     baz(up);
      |         ^~
      |         |
      |         unique_ptr<Bar,default_delete<Bar>>

我想知道如何解决这个问题。share_ptr似乎有适当的铸造方法来解决这个问题,而似乎unique_ptr没有其他选择。

标签: c++templatesunique-ptr

解决方案


首先,您正在baz 按 value接受论点,这意味着复制a std::unique_ptrand... 这是不可能的(或std::moveing 它,但我怀疑这就是您想要的)。

其次,std::unique_ptr不转换,因为那需要复制。

解决方法是什么?

你可以做:

std::unique_ptr<Foo<int>> up = std::make_unique<Bar>();

代替:

auto up = std::make_unique<Bar>();

baz 通过引用获取参数:

void baz(std::unique_ptr<Foo<int>>&) { ... }

首先是保存一个unique_ptrto 派生在一个unique_ptrto 基础中。auto不能这样做,除非你使用演员表。

第二件事是,如前所述,不要复制.unique_ptr

更重要的是,您的代码表现出未定义的行为,因为您使用基类指针删除了派生类对象。这需要virtual基类中的析构函数。


推荐阅读