我可以制作一个 unique_ptr 不获取其指向对象的所有权吗?

Posted

技术标签:

【中文标题】我可以制作一个 unique_ptr 不获取其指向对象的所有权吗?【英文标题】:Can I make a unique_ptr not to take the ownership of its pointed object? 【发布时间】:2013-10-16 14:25:19 【问题描述】:

我有一个唯一指针向量。其中,我希望一个不占用其指向对象的所有权。怎么做?

vector<unique_ptr<int>> v;
v.push_back(make_unique<int>(10));

unique_ptr<int> p(new int(20)); // add it to v but keep p take the ownership.

问题来自以下案例。我有一个由 GUI 树小部件表示的树结构数据。父节点使用vector&lt;unique_ptr&lt;T&gt;&gt; 获取其子节点的所有权。但有一个例外。我有一个常见的单例数据,并希望将其附加到树中以获取友好的用户界面。存在冲突,因为 sigleton 也取得了所有权。使用 share_ptr 可以,但会牺牲一些性能。

感谢大家的回答、cmets 和建议。这可能是一个设计缺陷。也许我需要一个带有vector&lt;unique_ptr&lt;T&gt;&gt;(对于其他人)和shared_ptr 的特殊父节点的新类,甚至是一个原始指针(对于单例)来处理异常。

【问题讨论】:

你为什么要这样做?动机是什么?使用原始指针? 你不能——这个名字是唯一的指针是有原因的。 为什么不使用shared_ptrweak_ptr 我不会卷入整个“单身狗烂”的圣战(不只是提及),但我仍然想知道你为什么想要vector&lt;unique_ptr&gt;如果您认为该资源应该归其他人所有? XY-Problem 警报。请说明你真正想做什么,而不是你想怎么做 【参考方案1】:

你想要一个不拥有它所指向的东西的unique_ptr

这些目标是相互矛盾的。 unique_ptr 的全部意义在于拥有它管理的资源。

在这里之后我很难推断出你是什么真正,因为你没有说你想要做什么 - 只是如何您正在尝试这样做。为什么你想要一个不拥有资源的unique_ptr

也许您真正追求的是shared_ptr,以便shared_ptr 的多个实例可以共享同一个对象的所有权。

再一次,也许您所追求的是weak_ptr,它本身并不(完全)“拥有”一个指针,直到它被提升为shared_ptr

阅读您的编辑后,我可能会预感到您在这里真正想要的是什么。你已经说过你希望你的单例对象真正拥有资源,但你仍然希望你的vector 有一个智能指针。也许您真正想要的是让vector 拥有一个不拥有对象本身的智能指针,但如果实际拥有的对象被销毁,它将变得无效或“无效”。

如果是这样,那么你的单例应该有一个shared_ptr,向量应该是一个vector&lt;weak_ptr&gt;。当您需要通过vector 实际获取对象时,您将调用lock 以提取shared_ptr - 检查来自lock 的返回以确保weak_ptr 没有过期。您也可以通过调用expired 来检查shared_ptr 是否已过期而不锁定它。

【讨论】:

+1,只是小评论。你不应该在lock() 之前测试expired();这是没有意义的,因为无论如何你都必须测试lock() 的结果(理论上它可能会在调用expired()lock() 之间过期)。【参考方案2】:

您不能使用普通的 unique_ptr&lt;int&gt; 来执行此操作 - 名称是 unique 指针,这是有原因的。

如果你真的很想这样做(但我 99.99% 确定这只是糟糕设计的征兆),你可以使用自定义删除器:

template <class T>
struct WeirdDeleter

  bool owning;
  explicit WeirdDeleter(bool owning = true) : owning(owning) 
  void operator() (const T *p) const 
    if (owning) delete p;
  
;


//Usage:

vector<unique_ptr<int, WeirdDeleter<int>>> v;
unqiue_ptr<int, WeirdDeleter<int>> p(new int(10));
v.push_back(std::move(p));

int *q = new int(20);
v.push_back(unique_ptr<int, WeirdDeleter<int>>(q, WeirdDeleter(false));

(我不知道关于删除器的建议make_unique 接口,所以我没有使用它;它仍然可以使用)。

重申一下,我认为这样做是一个坏主意(tm),但如果你真的想这样做,应该是这样。

【讨论】:

聪明,但我觉得有点太聪明了。 @JohnDibling 我努力表达我会避免使用它,但我知道有时情况(或老板)需要采取绝望的措施。 不,我明白了。我没有投反对票,实际上我 +1 了。我想我真的只是在强调你断言这是一个坏主意。 @JohnDibling 是的,我也是这么理解的。【参考方案3】:

unique_ptr 用于它具有独占所有权的确切用例。所以你不能用它来指向某物并且取得所有权。

解决方案很简单:改用shared_ptr。它没有独占所有权,相反,它指向同一个对象的所有实例都将共享所有权;只有当最后一个超出范围时,才会删除该对象。

如果您想要一个不影响所有权的指针,请查看weak_ptr

【讨论】:

A shared_ptr 仍然拥有该资源。请编辑您的答案,以便我能更好地理解您在这里的意思。 我有。现在好多了?但我猜你的答案还是好一点;) 这样更好,谢谢。我怀疑shared_ptr 仍然不是 OP 所追求的,但无论如何 +1。

以上是关于我可以制作一个 unique_ptr 不获取其指向对象的所有权吗?的主要内容,如果未能解决你的问题,请参考以下文章

指向 std::unique_ptr 的内容

如何在容器,ptrs和对象不可修改的情况下传递unique_ptrs容器?

自定义向量不支持 unique_ptr

C++ 中指向 unique_ptr 函数参数的原始指针的目的是啥?

移动持有 unique_ptr 的类实例

比较 std::unique_ptr 指向的底层(派生)类型