C++ unique_ptr 到派生类,作为将 unique_ptr 带入基类的函数的参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17473900/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:13:15  来源:igfitidea点击:

unique_ptr to a derived class as an argument to a function that takes a unique_ptr to a base class

c++visual-studio-2012c++11unique-ptr

提问by svick

I'm trying to use a unique_ptrto derived class in a function that takes a unique_ptrto a base class. Something like:

我正在尝试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);

If I understand this answercorrectly, this code should work, but it causes the following compile errors:

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

error C2664: 'f' : cannot convert parameter 1 from 'std::unique_ptr<_Ty>' to 'const std::unique_ptr<_Ty> &'

IntelliSense: no suitable user-defined conversion from "std::unique_ptr<Derived, std::default_delete<Derived>>" to "const std::unique_ptr<Base, std::default_delete<Base>>" exists

错误 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>>”的合适的用户定义转换

If I change fto take unique_ptr<Derived> const &derived, it works fine, but that's not what I want.

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

Am I doing something wrong? What can I do to work around this?

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

I'm using Visual Studio 2012.

我正在使用 Visual Studio 2012。

回答by Kerrek SB

You have three options:

您有三个选择:

  1. Give up ownership. This will leave your local variable without access to the dynamic object after the function call; the object has been transferred to the callee:

    f(std::move(derived));
    
  2. Change the signature of f:

    void f(std::unique_ptr<Derived> const &);
    
  3. Change the type of your variable:

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

    Or of course just:

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

    Or even:

    std::unique_ptr<base> derived = std::make_unique<Derived>();
    
  4. Update:Or, as recommended in the comments, don't transfer ownership at all:

    void f(Base & b);
    
    f(*derived);
    
  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);
    

回答by hmjd

A possibile solution is to change the type of the argument to be a Base const*, and pass derived.get()instead. There is no transfer of ownership with unique_ptr const<Base>&(and the unique_ptris not being modified), so changing to a Base const*does not change the meaning.

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



Herb Sutter discusses passing smart pointer arguments at length in Smart Pointer Parameters. An extract from the linked article refers to this exact situation:

Herb Sutter 在智能指针参数中讨论了按长度传递智能指针参数。链接文章的摘录是指这种确切情况:

Passing a const unique_ptr<widget>&is strange because it can accept only either nullor a widgetwhose lifetime happens to be managed in the calling code via a unique_ptr, and the callee generally shouldn't care about the caller's lifetime management choice. Passing widget*covers a strict superset of these cases and can accept “nullor a widget” regardless of the lifetime policy the caller happens to be using.

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

回答by David

I had option #1 of the accepted answer and I still had the same compile error. I banged my head on the wall for over an hour and I finally realized that I had

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

class Derived : Base {};

instead of

代替

class Derived : public Base {};