【问题标题】:Did I understand correctly the point of Scott Meyers' example of std::weak_ptr?我是否正确理解 Scott Meyers 的 std::weak_ptr 示例的要点?
【发布时间】:2015-07-19 15:45:55
【问题描述】:

Effective Modern C++(第 136 页)使用以下示例来激励std::weak_ptr。缓存被定义为一个无序映射,其中指向对象的弱指针作为值。每当这个缓存的客户端请求一个对象(按键)时,就会查找相应的弱指针并在其上调用lock()。如果结果 std::shared_ptr 不是 null,则返回它。否则,从外部数据库重新加载对象,进入缓存并返回std::shared_ptr

现在的问题是:有人可能认为没有std::weak_ptr 也可以实现这一点,而是将强共享指针存储为缓存值。如果强指针的use_count() 等于1,则表示所有客户端的指针都已销毁。这个例子的重点是使用std::weak_ptr 允许我们通过实际删除对象来节省内存吗?

【问题讨论】:

  • use_count 永远不会是一:当您插入新对象时,缓存中有一份副本,并且返回一份,因此使用次数为二。谁会回去扫缓存?
  • @KerrekSB 我认为您在谈论两件不同的事情。首先,当用户在他的副本上调用reset() 时,计数将再次变为1。当他继续从缓存中再次请求对象时,use_count() 将是一个。其次,没有人会去扫现金,这意味着实际对象不会被删除。但这只是意味着您对我的问题的回答是肯定的,对吗?

标签: c++ c++11 weak-ptr effective-c++


【解决方案1】:

“这个例子的重点是使用 std::weak_ptr 允许我们通过实际删除对象来节省内存吗?”

是的。否则,缓存将无限期地分配指向的资源。如果单独分配,控制块所需的空间通常远小于可能需要缓存的资源(例如纹理、网格数据,甚至本地化字符串)。

虽然可以使用原子实现相同的功能并检查引用计数是否为 1,但这需要自定义句柄实现。 std::weak_ptrstd::shared_ptr 使整个事情对原型的考验大大减少。

【讨论】:

  • 出现一个弹出窗口,提示我可以将此答案标记为已接受,但我找不到执行此操作的按钮...
  • @MeirGoldenberg 如果您将鼠标悬停在投票计数器下方的区域上,应该会出现一个勾勒出的复选标记。
  • 可能值得一提的是weak_ptr::lock() 是一个原子操作,但是检查use_count() == 1 然后对该信息进行操作不是原子操作。例如,在检查缓存中的use_count() == 1 之后,但在删除数据之前,另一个线程可能会检查缓存并说:我想要对该数据的引用!因此将use_count() 增加到2。然后第一个线程不必要地从缓存中删除shared_ptrweak_ptrs 和 weak_ptr::lock() 不会发生这种情况。
  • @HowardHinnant 是的。这就是为什么像use_count 这样的东西实际上只是调试辅助工具。实现我提到的原子检查的唯一方法是在 CAS 循环中,当检测到争用时,将中断并锁定整个表以验证引用更新(或者,如果它是 B 树,则只是那个叶子) .其他策略包括严格延迟加载资源,这可以减少查询站点的争用,同时将其分散到第一次使用资源的地方。
  • @MeirGoldenberg 如果lock 返回null,则该对象已经被删除,因此其他线程不可能“导致计数器增加”。
猜你喜欢
  • 2021-03-02
  • 2021-11-22
  • 2018-05-14
  • 2016-08-03
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 2012-04-16
  • 2019-11-15
相关资源
最近更新 更多