【问题标题】:Why does this implementation of COM IUnknown::Release work?为什么 COM IUnknown::Release 的这种实现有效?
【发布时间】:2011-06-19 11:35:33
【问题描述】:

从例子中我看到 COM IUnknown::Release() 函数实现是这样的:

ULONG Release()
{
    InterlockedDecrement(&m_count);
    if(m_count == 0) {
       delete this;
    }
    return m_count;
}

所以,如果 m_count 为 0,那么我们将删除“this”对象,并返回引用计数。 我不明白为什么它会起作用?!?!

  1. 删除对象不会破坏调用堆栈还是可以,因为它被线程持有,所以它与对象无关???

  2. 如果对象已被删除,我们怎么可能返回 m_count,它应该已被删除。我本可以说服自己,如果删除后代码返回硬编码的 0 也没关系,但它怎么会返回成员?!?!

非常感谢您的帮助! :-)

【问题讨论】:

  • +1 你是对的 - 要么这是错误代码,要么这里有一些更细微的工作。我很好奇是否有更多 COM 经验的人可以回答这个问题,但我的直觉是,这是完全错误的。

标签: c++ windows com


【解决方案1】:

那个代码是假的。在递减 之后,人们永远无法相信 m_count。正确的代码是这样总是

ULONG Release()
{
     ULONG count = InterlockedDecrement(&m_count);
     if(count == 0){ delete this; }
     return count;
}

【讨论】:

  • 您的意思是“ 删除之后”吗?
  • 不,他的意思是在递减之后。如果多个线程正在访问它,则可能另一个线程也调用了 Release,如果在递减和条件之间完成,则使成员变量的值为负。
  • 不,我的意思是在Decrement 之后。在delete 之后取消引用this 的问题是显而易见的,不需要重复。但是还有一个更微妙的并发问题。您的递减可能会使计数变为 2。当您再次触摸 m_count 时,由于您已经释放了计数,其他线程可能已经达到 0 并释放对象,并且插槽可能甚至被重新分配给其他东西。所以在递减 hic sunt leones 之后不要碰 m_count。
  • OP 并没有询问多线程。代码提到了它(通过互锁),但我认为 OP 只是从其他人的工作中复制/粘贴了这段代码。
  • 有可能,但不安全。内存在释放时不会被破坏,因此它可能包含以前的值并且“看起来”正确。但要靠运气。当您查看它时,另一个线程可能已经分配了完全相同的位置并更改了内容。如果你调用任何分配内存的东西,即使你自己的线程也可以重新分配相同的位置。
【解决方案2】:

您观察到的是未定义的行为。调用堆栈不会被delete this;delete this by itself is always safe 更改,而是renders this pointer invalid 这意味着你不能再取消引用它了。

您观察到的情况有两种可能的解释。从函数返回时,有问题的实现只是没有取消引用 this 指针以获取 m_count - 它已将其加载到寄存器并仅使用该值,因此 this 不会被取消引用,你不会观察任何问题或当delete 完成时,对象占用的内存仍然映射到进程地址空间并在技术上保持可访问性,因此取消引用this 成功并且m_count 被成功读取。我想后者的可能性更大。

无论解释是什么未定义的行为,你都不能依赖它,使用 user Remus Rusanu 建议的 in his answer

【讨论】:

    猜你喜欢
    • 2019-07-13
    • 2013-12-17
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 2015-06-15
    • 2017-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多