带有模板的upcast unique_ptr

时间:2019-03-09 10:07:09

标签: c++ templates 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似乎没有其他选择。

1 个答案:

答案 0 :(得分:2)

首先,您要在baz中按值取值 ,这意味着复制一个std::unique_ptr,并且...不可能(或std::move完成它,但我怀疑那是您想要的)。

第二,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_ptr派生到unique_ptr的基础。 auto无法做到这一点,除非您使用强制转换。

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

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