unique_ptr 到派生类作为函数的参数,该函数将 unique_ptr 带到基类
Posted
技术标签:
【中文标题】unique_ptr 到派生类作为函数的参数,该函数将 unique_ptr 带到基类【英文标题】:unique_ptr to a derived class as an argument to a function that takes a unique_ptr to a base class 【发布时间】:2013-07-02 16:08:18 【问题描述】:我正在尝试在将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);
如果我正确理解this answer,这段代码应该可以工作,但会导致以下编译错误:
错误 C2664: 'f' : 无法将参数 1 从 'std::unique_ptr<_ty>' 转换为 'const std::unique_ptr<_ty> &'
IntelliSense:不存在从“std::unique_ptr
>”到“const std::unique_ptr >”的合适的用户定义转换
如果我将f
更改为unique_ptr<Derived> const &derived
,它可以正常工作,但这不是我想要的。
我做错了吗?我可以做些什么来解决这个问题?
我正在使用 Visual Studio 2012。
【问题讨论】:
【参考方案1】:您有三个选择:
放弃所有权。这将使您的局部变量在函数调用后无法访问动态对象;对象已转移给被调用者:
f(std::move(derived));
更改f
的签名:
void f(std::unique_ptr<Derived> const &);
更改变量的类型:
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>();
更新:或者,按照 cmets 的建议,根本不要转让所有权:
void f(Base & b);
f(*derived);
【讨论】:
在这种情况下,我正在考虑使用 4。使用shared_ptr
。
在函数调用中使用引用而不是 unique_ptr 怎么样?
@svick,如果它不拥有指针的所有权,为什么还要将智能指针传递给函数?这不是智能指针的用途。
@metal:太好了,谢谢 - 是的,重要的细节,返回类型必须匹配。我错过了。好东西。你可以说return std::unique_ptr<Base>(std::move(p))
,我想。
“这将在函数调用结束时销毁对象”:但是我们不知道f()
在做什么(假设它实际上不是空的) - 它可能会将所有权转移到其他地方。我们不能说我们放弃或转让所有权吗?【参考方案2】:
我有接受答案的选项#1,但我仍然遇到相同的编译错误。我把头撞在墙上一个多小时,我终于意识到我有
class Derived : Base ;
而不是
class Derived : public Base ;
【讨论】:
【参考方案3】:一个可能的解决方案是将参数的类型更改为Base const*
,并改为传递derived.get()
。 unique_ptr const<Base>&
没有所有权转移(并且unique_ptr
没有被修改),因此更改为Base const*
不会改变含义。
Herb Sutter 在Smart Pointer Parameters 中详细讨论了传递智能指针参数。链接文章的摘录指的是这种确切的情况:
传递
const unique_ptr<widget>&
很奇怪,因为它只能接受null
或widget
,其生命周期恰好通过unique_ptr
在调用代码中进行管理,而被调用者通常不应该关心呼叫者的终生管理选择。传递widget*
涵盖了这些情况的严格超集,并且可以接受“null
或widget
”,而不管调用者使用的生命周期策略如何。
【讨论】:
Base const*
不是意味着该函数可以将指针存储在某处吗?我虽然智能指针试图避免这种情况。
@svick,该函数可以同样轻松地存储base.get()
(get()
是const
成员函数)。
@svick 否。智能指针通过明确谁是对象的所有者来避免内存泄漏。如果您将原始指针作为参数传递给函数,您只需授予读取/修改它的权限。智能指针是为了避免使用原始的new
和delete
,而不是指针。【参考方案4】:
另一种方法是更改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
【讨论】:
以上是关于unique_ptr 到派生类作为函数的参数,该函数将 unique_ptr 带到基类的主要内容,如果未能解决你的问题,请参考以下文章