92

我试图在一个接受基类unique_ptr的函数中使用一个派生unique_ptr类。就像是:

class Base {};

class Derived : public Base {};

void f(unique_ptr<Base> const &base) {}

…

unique_ptr<Derived> derived = unique_ptr<Derived>(new Derived);
f(derived);

如果我正确理解了这个答案,这段代码应该可以工作,但它会导致以下编译错误:

错误 C2664:“f”:无法将参数 1 从“std::unique_ptr<_Ty>”转换为“const std::unique_ptr<_Ty> &”

IntelliSense:不存在从“std::unique_ptr<Derived, std::default_delete<Derived>>”到“const std::unique_ptr<Base, std::default_delete<Base>>”的合适的用户定义转换

如果我f改为 take unique_ptr<Derived> const &derived,它可以正常工作,但这不是我想要的。

难道我做错了什么?我能做些什么来解决这个问题?

我正在使用 Visual Studio 2012。

4

4 回答 4

95

你有三个选择:

  1. 放弃所有权。这将使您的局部变量在函数调用后无法访问动态对象;对象已转移给被调用者:

    f(std::move(derived));
    
  2. 更改签名f

    void f(std::unique_ptr<Derived> const &);
    
  3. 更改变量的类型:

    std::unique_ptr<base> derived = std::unique_ptr<Derived>(new Derived);
    

    或者当然只是:

    std::unique_ptr<base> derived(new Derived);
    

    甚至:

    std::unique_ptr<base> derived = std::make_unique<Derived>();
    
  4. 更新:或者,按照评论中的建议,根本不要转让所有权:

    void f(Base & b);
    
    f(*derived);
    
于 2013-07-04T15:32:34.890 回答
35

我有接受答案的选项#1,但我仍然有相同的编译错误。我把头撞在墙上一个多小时,我终于意识到我有

class Derived : Base {};

代替

class Derived : public Base {};
于 2019-06-09T19:40:48.737 回答
13

一个可能的解决方案是将参数的类型更改为 a Base const*,然后通过derived.get()。with 没有所有权转移unique_ptr const<Base>&(并且 theunique_ptr没有被修改),因此更改为 aBase const*不会改变含义。


Herb Sutter 在Smart Pointer Parameters中详细讨论了传递智能指针参数。链接文章的摘录指的是这种确切的情况:

传递 aconst unique_ptr<widget>&很奇怪,因为它只能接受一个null或 a widget,其生命周期恰好在调用代码中通过 a 进行管理unique_ptr,并且被调用者通常不应该关心调用者的生命周期管理选择。传递widget*涵盖了这些情况的严格超集,并且可以接受“<code>null 或 a widget”,而不管调用者碰巧使用的生命周期策略如何。

于 2013-07-04T15:52:14.227 回答
-1

另一种方法是更改​​签名f并以稍微不同的方式使用它:

void f(Base* base_ptr) {
    // take ownership inside the function
    std::unique_ptr<Base> base {base_ptr};
    // ...
}

// ...
auto derived = std::make_unique<Derived>();
f(derived.release());  // release ownership
于 2021-07-14T11:45:44.127 回答