【问题标题】:Upcast unique_ptr with template使用模板向上转换 unique_ptr
【发布时间】:2019-03-09 10:07:08
【问题描述】:

考虑以下简单代码:

#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 似乎没有其他选择。

【问题讨论】:

  • Foo 需要一个 virtual 析构函数
  • 您的代码无法按原样工作,因为无法复制 std::unique_ptr。鄙视,你为什么需要在这里传递std::unique_ptr?使用没有所有权的原始指针并不是一件坏事。

标签: c++ templates unique-ptr


【解决方案1】:

首先,您在baz 中采用参数按值,这意味着复制 std::unique_ptr 并且...这是不可能的(或@ 987654323@ing 它,但我怀疑这就是你想要的)。

其次,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 析构函数。

【讨论】:

  • Ops... 对,我只是忘了移动!真丢人!顺便说一句,使用引用方法意味着我可以在不移动的情况下传递唯一指针,但这可能不清楚baz 函数是否会在内部移动,对吗?所以在我的情况下,我更愿意强制采取行动。
  • 通过非const 引用传递并不意味着该对象是只读的,因此std::move 将是有效的,但你是对的 - 通过值(或通过右值引用)获取它, 这需要移动会更好地暗示baz 将在内部移动。
  • 你确定你可以通过引用传递up吗?
  • @n.m 你能详细说明一下吗?您是否关心实际的用例逻辑(OP 在上面的评论中澄清了这一点 - 他实际上更喜欢通过 &amp; 传递)或语法正确性?
猜你喜欢
  • 2016-07-23
  • 2013-08-19
  • 2015-08-08
  • 2019-05-24
  • 2013-07-10
  • 1970-01-01
  • 2021-12-30
  • 2018-12-15
  • 1970-01-01
相关资源
最近更新 更多