能否使unique_ptr不接管其所指向的对象所有权?

3

我有一个独特指针的向量。其中,我想让其中一个指针不接管其所指向的对象。如何实现?

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<unique_ptr<T>>拥有其子元素。但是有一个例外。我有一个常见的单例数据,并且也想将其附加到树上以获得友好的用户界面。这里存在冲突,因为单例也拥有所有权。使用share_ptr可以解决问题,但会牺牲一些性能。

感谢大家的答案、评论和建议。这可能是设计上的缺陷。也许我需要一个新类来处理特殊的父节点,使用vector<unique_ptr<T>>(用于其他)和shared_ptr甚至是原始指针(用于单例)。


1
你为什么想要这样做?动机是什么?使用原始指针吗? - Nawaz
2
为什么不使用shared_ptrweak_ptr呢? - Nate Chandler
@Nawaz 我在那里展示我的案例。 - user1899020
4
我不打算卷入整个“单例模式糟糕”的圣战(仅仅是提一下),但如果你认为资源应该由其他东西拥有,我仍然想知道为什么你要使用vector<unique_ptr> - John Dibling
1
XY-Problem 警告。请澄清您实际想要做什么,而不是如何做它。 - codeling
显示剩余2条评论
3个回答

8
您想要一个不拥有所指对象的unique_ptr。
这两个目标是相互矛盾的。unique_ptr的整个意义在于拥有它管理的资源。
很难推断您真正想要什么,因为您没有说出您要做什么,只说了您要怎么做。为什么您想要一个不拥有资源的unique_ptr呢?
也许您真正需要的是shared_ptr,这样多个shared_ptr实例可以共享同一个对象的所有权。
或者,也许您真正需要的是weak_ptr,它本身并没有(完全)“拥有”指针,直到被晋升为shared_ptr。
阅读完您的编辑后,我可能有一些猜测。您说过您希望单例对象实际上拥有资源,但您仍想让vector具有智能指针。也许您真正需要的是vector具有智能指针,但它本身不拥有该对象,但如果实际拥有的对象被销毁,则会失效或“取消选择”。
如果是这种情况,那么您的单例应该有一个shared_ptr,并且vector应该是一个vector 。当您需要通过vector实际获取对象时,您将调用lock来提取shared_ptr -- 检查lock的返回值以确保weak_ptr未过期。您还可以通过调用expired而不锁定它来检查shared_ptr是否已过期。

+1,只是小注释。在lock()之前不应该测试expired();这是毫无意义的,因为您必须在任何情况下都要测试lock()的结果(在调用expired()lock()之间它可能会过期)。 - Angew is no longer proud of SO

4
您不能使用普通的unique_ptr<int>来实现这个功能 - 它的名字是“独特指针”,有其原因。
如果您真的非常想这样做(但我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 接口,所以没有使用它;但它仍然可用。

再次强调,我认为这是一个不好的想法,但如果你真的想要,这应该是正确的方法。


聪明,但我认为有点过于聪明了。 - John Dibling
@JohnDibling 我曾努力沟通,建议避免使用这种方法。但是我知道有时候情况(或老板)会迫使我们采取不得已的措施。 - Angew is no longer proud of SO
不,我明白。我没有给你的回答投反对票,事实上我点了赞。我想我只是在强调你所说的这是一个坏主意。 - John Dibling
@JohnDibling 是的,我也是这样理解的。 - Angew is no longer proud of SO

3
unique_ptr的使用场景是具有独占所有权。因此,您不能将其用于指向某物并且拥有所有权的情况。
解决方案很简单:改用shared_ptr。它没有独占所有权,而是所有指向同一对象的实例将共享所有权;只有在最后一个实例超出范围时,该对象才会被删除。
如果您需要一个不干扰所有权的指针,请看看weak_ptr

1
一个 shared_ptr 仍然拥有资源。请编辑您的回答,以便我更好地理解您在这里的意思。 - John Dibling
我现在好多了?但是你的答案还是更好一点,我猜 ;) - codeling
好的,谢谢。我怀疑shared_ptr仍然不是OP想要的,但无论如何还是+1。 - John Dibling

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