【问题标题】:Enforce safe use of class containing reference or raw pointer强制安全使用包含引用或原始指针的类
【发布时间】:2015-03-17 01:24:59
【问题描述】:

假设我们有一个如下所示的类。

class DoStuffWithRef
{
    DoStuffWithRef(LargeObject& lo) : lo_(lo) {}

    // a bunch of member functions, some of them useful
    // [...]

private:
    LargeObject& lo_;
};

该类的设计使得唯一合理的用途是当至少一个其他实体拥有lo_ 引用的对象的所有权时。如果客户端代码适当地使用该类,则DoStuffWithRef 无需拥有LargeObject 的所有权。

如果类被滥用,是否有办法强制执行此用法或发出错误信号?除了记录DoStuffWithRef 的预期用途之外,还能做些什么吗?

例如,自动存储的DoStuffWithRef 可能引用自动存储的LargeObject

void foo()
{
    LargeObject lo;
    DoStuffWithRef dswr(lo);
    // some code that makes use of the DoStuffWithRef instance
    return;
}

这是我想到的主要用途,尽管还有其他可能的情况可以保证其他人拥有所有权。

问题是客户端代码很可能会创建一个DoStuffWithRef 实例,该实例最终会产生一个悬空引用。如果没有其他人拥有由DoStuffWithRef 引用的LargeObject 的所有权,那么当DoStuffWithRef 尝试访问LargeObject 时就会出现混乱。更糟糕的是,只有在错误发生很久之后才会出现混乱。

当这在过去出现时,我使用了 boost::shared_ptr<> 而不是引用(这是在 C++03 中)。这并不能恰当地表达类的语义。前提是DoStuffWithRef 不需要所有权——它的目的是作用于他人拥有的对象,如果没有其他人拥有该对象,那么DoStuffWithRef 提供的功能就没有任何意义。将所有权授予DoStuffWithRef 会产生不必要的开销并强制共享所有权语义。 weak_ptr<> 也会有错误的语义,因为我们不应该在运行时询问指针是否有效。

我从来没有在代码的性能敏感部分或共享所有权是一个重大负担的情况下出现这种情况,所以这并不重要,但我希望我知道一种准确表达这一点的方法在 C++ 中。成本很小,但它们也是不必要的。更重要的是,shared_ptr<> 将隐藏该类的错误使用。如果修改为使用shared_ptr<>DoStuffWithRefLargeObject 的唯一剩余所有者,则在短期内避免了悬空引用,但客户端代码最终处于未知领域。

【问题讨论】:

标签: c++ smart-pointers ownership data-members


【解决方案1】:

DoStuffWithRef 是否有其他状态?如果不是,它似乎是一堆实用函数。对 LargeObject 的引用也可以作为参数传递给每个函数。这也解决了所有权问题。

否则,如果它是有状态的,这显然是共享所有权的情况,因为 DoStuffWithRef 确实需要将 LargeObject 的单个活动实例的生命周期延长到其自身的生命周期。或者,使用弱指针并吃掉运行时检查的成本......

【讨论】:

  • 它可能是一个将数据成员用作“函数参数”的函数对象。它可以说有状态,但肯定不会有可变状态。使用函数对象而不是函数的原因可能是我们想对其进行参数化,然后使用它来创建其他函数对象。
  • 好的。对我来说,您提到函数对象这一事实实际上意味着它应该是一个共享指针。由于您正在传递捕获的原始引用,因此它本质上是危险的。
  • 我的意思是,特别是如果你开始编写函数对象等,很快你就会在不同的线程等上使用它。除非你对所有权有严格的要求,否则这样会很痛苦。 :)
  • 如果我们坚持客户端代码无限制地使用函数对象,您的观点是正确的,但是如果我们只打算在同一范围内创建和使用函数对象呢?跨度>
  • 嗯.. 我不明白它是如何静态执行的。例如。 std::function 使用类型擦除,这可能是一种方式。如果这个对象打算在有限的上下文中使用,我可能会将它放在“详细信息”子命名空间中,并将其称为实现细节。 IE。除了确保它不是“公开的”之外,不要担心它。
猜你喜欢
  • 2019-08-14
  • 2023-01-08
  • 2014-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多