如何将std::unique_ptr转换为超类的std::unique_ptr?

7
假设我有一个名为foo的类,它从一个名为bar的类继承而来。
我有一个指向foo实例的std :: unique_ptr ,我想将其传递给一个只接受std :: unique_ptr<bar>的函数。如何转换指针以使其在我的函数中起作用?

foo 是一个多态实例吗? - Mahesh
2
让任何不关心内存来源或之后发生什么的函数,通过引用(或原始指针如果可能为空)来获取参数。 - Neil Kirk
1
@NeilKirk:这个函数可以工作,但在集合中存储unique_ptr<Base>是一个合理的用例。如果该函数必须存储它... - Matthieu M.
unique_ptr 没有复制构造函数,因此一个名为 f(std::unique_prt<T> p) 的函数不能在没有使用 std::move 的情况下被调用。也许你的意思是函数应该接受一个右值引用或左值引用? - Walter
4个回答

27

您可以将 std::unique_ptr<foo> 右值转换为 std::unique_ptr<bar>

std::unique_ptr<foo> f(new foo);
std::unique_ptr<bar> b(std::move(f));

显然,指针将由b拥有,如果b被销毁,则bar需要具有一个虚析构函数


2

由于继承,不需要特别处理。如果想要将unique_ptr传递给函数,需要使用std::move,即使类型相同也是如此:

#include <memory>

struct A {
};

struct B : A {
};

static void f(std::unique_ptr<A>)
{
}

int main(int,char**)
{
  std::unique_ptr<B> b_ptr(new B);
  f(std::move(b_ptr));
}

0
您可以使用以下语法:

std::unique_ptr<parent> parentptr = std::unique_ptr<child>(childptr);

或者您可以使用std::move

另一个选项是发出原始指针,但您需要更改函数:

void func(const parent* ptr)
{
  // actions...
}
func(*childptr);

这是一篇关于智能指针和将其传递给函数的好文章:http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters


-1
你无法这样做,因为它会违反最基本的unique_ptr规则:必须只能有一个实例持有给定指针,而unique_ptr完全拥有它(当它超出作用域时,指向的对象被删除)。 unique_ptr和unique_ptr(其中U:T)不兼容,就像你已经看到的一样。
对于shared_ptr,您可以拥有多个实例,它具有行为类似于static_cast的std::static_pointer_cast,除了它接受一个shared_ptr并返回另一个shared_ptr(两者都指向同一个对象)。
如果您绝对需要使用unique_ptr,则必须创建一个函数,首先取消当前unique_ptr的所有权,并将该指针放入正确类型的新unique_ptr中。在函数调用后,您可能还需要执行相反的转换。

1
+1. 为了完整性,std::dynamic_pointer_cast<>std::const_pointer_cast<>存在于其他常见的指针转换中。 - justin
3
当然可以,你只需要转让所有权就行了,显然。 - Matthieu M.
1
@zneak:就像什么?base.reset(derived.release())是安全的(除了在VS中...),base = std::move(derived)也是安全的(而且更符合惯用法)。我不太明白为什么你要创建一个函数来做这件事,因为它写起来很简短。 - Matthieu M.
1
@zneak:我已经读了你的评论两遍,但恐怕我还是不明白你想说什么 :'( 如果你能提供一个示例代码来说明问题,我将不胜感激。 - Matthieu M.
1
@zneak: 我不同意,尽管这是一个资格问题。unique_ptr即使在所有权转移方面也提供了基本异常保证,因此是安全的。您编写的代码无法提供强异常保证(似乎您希望如此),这是您代码的问题。 - Matthieu M.
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接