将派生类的unique_ptr用作将unique_ptr用作基类的函数的参数


73

我正在尝试unique_ptr在将aunique_ptr用作基类的函数中使用to派生类。就像是:

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 <派生,std :: default_delete <派生>>”到“ const std :: unique_ptr <基本,std :: default_delete <基本>>”的合适的用户定义转换

如果我更改f为take unique_ptr<Derived> const &derived,则效果很好,但这不是我想要的。

难道我做错了什么?我该怎么办才能解决此问题?

我正在使用Visual Studio 2012。

Answers:


76

您有三种选择:

  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);
    

1
在这种情况下,我正在考虑使用4. Use shared_ptr
svick

4
仅使用引用而不是函数调用的unique_ptr怎么样?
ltjax

16
@svick,如果不获取指针的所有权,为什么还要将智能指针传递给该函数?那不是智能指针的目的。
Jonathan Wakely

@ltjax我该怎么做?
2013年

2
@metal:太好了,谢谢-是的,重要的细节,返回类型必须匹配。我错过了。好东西。return std::unique_ptr<Base>(std::move(p))我想你可能已经说过了。
Kerrek SB 2014年

14

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

class Derived : Base {};

代替

class Derived : public Base {};

12

一种可行的解决方案是将参数的类型更改为Base const*,然后传递derived.get()。没有所有权转让unique_ptr const<Base>&(且unique_ptr不会被修改),因此更改为aBase const*不会改变含义。


香草萨特讨论了在长传递智能指针参数智能指针参数。链接文章的摘录涉及此确切情况:

传递aconst unique_ptr<widget>&是很奇怪的,因为它只能接受,null或者只能通过接受widget在调用代码中管理其生命周期的生命unique_ptr,并且被调用方通常不必关心调用方的生命周期管理选择。传递widget*涵盖了这些情况的严格超集,并且可以接受“nullwidget”,而与呼叫者恰巧使用的生存期策略无关。


1
并不Base const*意味着该函数可以将指针存储在某个地方吗?我虽然聪明的指针试图避免这种情况。
svick

@svick,该函数可以base.get()轻松存储(get()const成员函数)。
hmjd

2
@svick否。智能指针通过明确谁是对象的所有者来避免内存泄漏。如果将原始指针作为参数传递给函数,则只需授予对其进行读取/修改的权限。智能指针应避免使用rawnewdelete,而不要完全使用指针。
etam1024
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.