shared_ptr<> 对 weak_ptr<> 就像 unique_ptr<> 对...什么?

新手上路,请多包涵

在 C++11 中,您可以使用 shared_ptr<> 与对象或变量建立所有权关系,并使用 weak_ptr<> 以非拥有方式安全地引用该对象。

您还可以使用 unique_ptr<> 与对象或变量建立所有权关系。但是,如果其他非拥有对象也想引用该对象怎么办? weak_ptr<> 在这种情况下没有帮助。原始指针很有帮助,但也带来了各种缺点(例如,它们可以 自动初始化为 nullptr ,但这是通过与 std::*_ptr<> 类型不一致的技术来实现的)。

对于通过 unique_ptr<> 拥有的对象的非拥有引用, weak_ptr<> 的等价物是什么?

这是一个清晰的示例,类似于我正在开发的游戏中的某些内容。

 class World
{
public:

    Trebuchet* trebuchet() const { return m_trebuchet.get(); }

private:
    std::unique_ptr< Trebuchet > m_trebuchet;
};

class Victim
{
public:
    Victim( Trebuchet* theTrebuchet ) : m_trebuchet( theTrebuchet ) {}

    ~Victim()
    {
        delete m_trebuchet;     // Duh. Oops. Dumb error. Nice if the compiler helped prevent this.
    }

private:

    Trebuchet* m_trebuchet;    // Non-owning.
};

shared_ptr< Victim > createVictim( World& world )
{
    return make_shared< Victim >( world.trebuchet() );
}

在这里,我们使用原始指针来维护与通过 unique_ptr<> 在其他地方拥有的对象的非拥有关系。但是,我们能做到最好吗?

希望是一种指针,它:

  • 看起来像其他现代指针类型。例如 std::raw_ptr<T>
  • 替换原始指针,以便始终使用现代指针类型的代码库可以通过搜索 _ptr< (大致)找到 所有 指针。
  • 自动初始化为 nullptr。

因此:

 int* p;                  // Unknown value.
std::raw_ptr< int > p;   // null.

这种类型现在是否已经存在于 C++ 中,是为未来提出的,还是在例如 Boost 中广泛可用的另一种实现?

原文由 OldPeculier 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 507
2 个回答

确实需要一种标准指针类型来充当 std::unique_ptr<> 的非拥有、廉价且行为良好的对立面。目前还没有这样的指针被标准化,但是 已经提出了一个标准,并且正在由 C++ 标准委员会讨论。 “世界上最愚蠢的智能指针”,又名 std::exempt_ptr<> 将具有其他现代 C++ 指针类的一般语义,但对于拥有指向对象(如 shared_ptrunique_ptr 做)或正确响应该对象的删除(如 weak_ptr 做)。

假设这个特性最终得到委员会的批准,它将完全满足这个问题中强调的需求。即使没有得到委员会的批准,上述链接文件也充分表达了需求并描述了一个完整的解决方案。

原文由 OldPeculier 发布,翻译遵循 CC BY-SA 3.0 许可协议

shared_ptr 的“通知”行为需要对引用计数控制块进行引用计数。 shared_ptr 的引用计数控制块为此使用单独的引用计数。 weak_ptr 实例维护对此块的引用,并且 weak_ptr s 本身阻止引用计数控制块被 delete ed。当强计数变为零时,指向的对象会调用其析构函数(这可能会或可能不会导致存储该对象的内存的 delete 离子),并且控制块是 delete 仅在弱引用计数变为零时编辑。

unique_ptr 的原则是它比普通指针的开销为零。分配和维护引用计数控制块(以支持 weak_ptr -ish 语义)打破了这一原则。如果您需要该描述的行为,那么您确实需要共享语义,即使对该对象的其他引用是非拥有的。在这种情况下,共享仍然在进行——共享对象是否已被销毁的状态。

如果您需要通用的非拥有引用并且不需要通知,请使用纯指针或纯引用 unique_ptr 中的项目。


编辑:

在您的示例中,看起来 Victim 应该要求 Trebuchet& 而不是 Trebuchet* 。然后很清楚谁拥有该对象。

 class World
{
public:

    Trebuchet& trebuchet() const { return *m_trebuchet.get(); }

private:
    std::unique_ptr< Trebuchet > m_trebuchet;
};

class Victim
{
public:
    Victim( Trebuchet& theTrebuchet ) : m_trebuchet( theTrebuchet ) {}

    ~Victim()
    {
        delete m_trebuchet;     // Compiler error. :)
    }

private:

    Trebuchet& m_trebuchet;    // Non-owning.
};

shared_ptr< Victim > createVictim( World& world )
{
    return make_shared< Victim >( world.trebuchet() );
}

原文由 Billy ONeal 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题