可以在标准弱指针之上实现一个非拥有的“稍微智能”的指针吗?

3

我一直在思考,虽然我理解std::observer_ptr的目标,但我认为如果有一个类似的指针类型知道它所指向的对象是否已被删除,那将是很好的。例如,我们可以有以下内容:

slightly_smart_ptr<Foo> p1(new Foo());
auto p2 = p1;
p1.erase(); // This deletes the foo referred to by p1.
if (p2.expired())
   std::cout << "p2 is expired\n"; // this will fire

当前标准库中实现此功能的一种方法是,在某个 A 的生命周期将存在的作用域中创建指向 A 的 shared_ptr,始终通过传递 weak_ptr 引用 A,并在不再需要 A 时通过重置 shared_ptr 来删除 A。这里的 weak_ptr 具有 observer_ptrs 的基本语义,知道 A 是否已被删除。但是,这种方法存在问题:必须锁定 weak_ptr,将其转换为 shared_ptr 以便使用,这感觉很不整洁,而且更严重的是,需要在某处存在指向 A 的 shared_ptr,当用户只想要一个稍微智能一些的指针时,该指针并不拥有任何内容。用户同意在适当的时候手动销毁内容:不存在共享所有权,因此在这种情况下创建 shared_ptr 是一种代码异味。
我无法想到隐藏此实现细节的有效方法。
另外,是否存在此类指针的提案或者在 boost 库或其他地方?

2
有些棘手。弱指针需要锁定的一个重要原因是为了防止在使用分配时部分释放分配。如果您只想知道“此时此刻指针是否有效?”,那么锁定它就过度了,但我不认为替代方案有多大意义。测试后立即可能会消失分配。您是否需要有关释放的通知? - user4581301
7
我认为使用 shared_ptrweak_ptr 并没有问题。无论你如何设计,都需要对对象进行锁定,以防止一个指针在另一个指针使用它时删除它。 - super
如果你只想知道“指针在这个时间点是否有效?”,那么锁定它就过度了,但我不认为选择另一种方式有多大意义。我的意思是,如果不锁定,那么 slightly_smart_ptr<T> 就不会是线程安全的,对吧?但 shared_ptr 的一个重要批评是,即使你不需要它,你也要为线程安全付出代价。 - jwezorek
1
@jwezorek 不仅如此,还有 if(ptr.valid()) { stuff(); ptr->a; }stuff() 函数可能使指针无效,所以你必须在每个语句之前进行检查。 - Guillaume Racicot
稍微重新考虑一下。根据现有问题所写,已经有了很好的答案。你最好是提出一个新问题,而不是无效化它们。 - user4581301
显示剩余4条评论
2个回答

6
一般情况下不可行。
现有智能指针的整个目的是以一种通常使用裸指针无法实现的方式来跟踪对象的生命周期和所有权,除非你钩入分配器并且在分配给定对象的任何句柄之间存在一些复杂的关系。
您描述的好处正是使用所述现有智能指针时带来的好处。 在这里,shared_ptr和weak_ptr非常适合。
锁定没有问题(您需要此功能),而且没有必要在某个地方有一个shared_ptr,因为肯定有人拥有该数据。 如果他们没有,您的设计会有更大的问题,并且您正在尝试使用类似的破损智能指针概念绕过这些问题,但这些概念将永远不存在于标准中。

6
这种智能指针的问题在于,它比 std::unique_ptr、T* 或 std::weak_ptr 更容易出错。当您想知道指针是否已被其唯一所有者从其他地方删除时,实际上您需要共享拥有权和 std::weak_ptr。您需要“锁定”一个弱指针才能使用它,这是因为当您开始使用它时,您会获得指针的所有权。如果您无法锁定您的“观察者指针以了解是否已删除”,则不能安全地使用它,因为在验证其有效性后的任何时刻都可能被删除。此外,您还有更深层次的矛盾。如果您拥有唯一的指针,则知道谁将删除它,并知道谁是所有者。如果您有一个检查指针运行时有效性的程序,则是因为您的程序不知道资源的所有权状态。如果您的程序或部分程序无法知道资源的所有权状态并且需要检查它是否已被删除,则需要确保在使用它时不会在下一行被删除,因为您无法知道其所有权状态。因此,您需要共享所有权以推迟在执行代码时做出所有权决策。如果您具有共享所有权,则不需要“观察者指针以了解是否已删除”。那么您的指针就不需要存在了。那么...您认为您需要那个指针,它可能很方便...该怎么办?您需要检查您的代码。如果只有一个所有权,为什么需要知道指针的有效性。为什么不能直接询问所有者?如果所有者不存在,则希望进行检查的代码可能在所有者删除时无效。也许您想要进行检查的结构应该与所有者同时终止。如果您的唯一所有者在不可预测的时刻死亡(例如,您的唯一所有者由共享所有者持有),则您的结构应检查共享所有者的有效性。也许调用希望检查其指针是否仍然有效的函数的代码在所有者死亡时根本不应该调用它。等等。有很多种方法可以解决这个问题,但通常需要在唯一所有者上需要弱指针表明程序中存在缺陷或对象生命周期推理中存在问题。

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