将带有自定义删除器的unique_ptr转移到shared_ptr

28

我有一个函数,它使用自定义删除器创建unique_ptr并返回:

auto give_unique_ptr() {
    auto deleter = [](int* pi) {
        delete pi;
    };
    int* i = new int{1234};
    return std::unique_ptr<int, decltype(deleter)>(i, deleter);
}

在该函数的客户端代码中,我想将unique_ptr移动到shared_ptr中,但鉴于我不知道函数之外自定义删除器的decltype,我不知道如何做。

我猜应该是这样的:

auto uniquePtr = give_unique_ptr();
auto sharedPtr = std::shared_ptr<..??..>(std::move(uniquePtr));

我需要写什么而不是..??..才能得到正确的类型?

如果可能的话,当shared_ptr的使用计数为零时,它会像预期一样使用我在give_unique_ptr()函数中创建的自定义删除器吗?


请记住,shared_ptr 擦除了删除器。当前视图中唯一的模板参数是指向的类型。 - o11c
@o11c是什么意思?我尝试了@Nawaz提出的解决方案,发现在销毁'shared_ptr'之后会调用'deleter'。 - j00hi
这意味着删除器的类型与shared_ptr的类型无关。你甚至可以将其转换为shared_ptr<char>,它仍然会调用原始的删除器。 - o11c
2个回答

19

如果您知道(或希望明确输入)对象的类型,则可以进行以下操作:

std::shared_ptr<int> sharedPtr(std::move(uniquePtr));

std::shared_ptr的构造函数将负责处理删除器。


如果你想推断类型,则:


auto sharedPtr = make_shared_from(std::move(uniquePtr));

其中make_shared_from是:

template<typename T, typename D>
std::shared_ptr<T> make_shared_from(std::unique_ptr<T,D> && p)
{
   //D is deduced but it is of no use here!
   //We need only `T` here, the rest will be taken 
   //care by the constructor of shared_ptr
   return std::shared_ptr<T>(std::move(p));
};

希望这能帮到你。

2
在我看来,make_shared_from 最好采用右值引用,以使其从外部可见,表明它正在被移动。 - Ryan Haining
3
在大多数情况下,使用C++11的风格更具特色,甚至是值传递。 - o11c
1
@o11c,我不能说我同意,除了产生额外的移动之外,还有什么区别吗? - Ryan Haining
2
@o11c shared_ptr 的构造函数接受一个 unique_ptr&&,因此采用取值方式调用并不是更加“惯用”。自定义删除器可能会变得更大,以至于额外的移动操作并不像你想象的那样微不足道。因此建议直接传递。指针的移动是微不足道的,但 unique_ptr 的移动则不然。 - Ryan Haining
3
即使您只有一个接收sink参数的类型,使用&&来表示是有意义且符合惯用法的。在内联函数中,所有这些寄存器/指针计数都不重要。同时,@Ryan提出的“我们不知道自定义删除器的成本”也很好。我个人会选择std::shared_ptr<T> share_unique_ptr(std::unique_ptr<T,D>&& ptr)作为函数名称/签名:返回共享指针的事实应该是函数名称的一部分。 - Yakk - Adam Nevraumont
显示剩余8条评论

16
auto uniquePtr = give_unique_ptr();
auto sharedPtr = std::shared_ptr<decltype(uniquePtr)::element_type>(std::move(uniquePtr));

是的,shared_ptr 将会保存并在后续使用自定义删除器。


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