在 COM 中奇怪地使用空智能指针

Strange use of null smart pointer in COM

如图所示,不知道为什么m_spServer,一个接口指针,当测试为null时,可以用来调用一个成员函数CreateInstance()。谁能告诉我为什么?

这是接口定义,我在接口中没有找到CreateInstance(),也没有找到接口指针定义。

仔细看代码:

m_spServer.CoCreateInstance(...);

需要注意两点:

  1. m_spSever 不是一个真正的指针。相反,它是类型 CComPtr 智能指针 模板 class 的一个实例。也就是说,它重载了 -> 运算符以取消引用底层原始指针 (IAtlasServer*)。同样,== 运算符被重载以测试是否为空。

  2. 方法被调用为 .CoCreateInstance 和 "dot"。不是 ->CoCreateInstance 和 "arrow"。智能指针永远不会是"null"。它包含的指针可能是。这意味着该方法是在 CComPtr 实例本身上调用的,而不是在底层原始指针上。

让我们看看 CComPtr::CoCreateInstance 的实现。

template <class T>
class CComPtrBase
{
    ...

    bool operator==(_In_opt_ T* pT) const throw()
    {
        return p == pT;
    }

    ...

    _Check_return_ HRESULT CoCreateInstance(
        _In_ REFCLSID rclsid,
        _Inout_opt_ LPUNKNOWN pUnkOuter = NULL,
        _In_ DWORD dwClsContext = CLSCTX_ALL) throw()
    {
        ATLASSERT(p == NULL);
        return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p);
    }

    ...

    T* p;

    ...
};

您会看到 CComPtr 包装了一个名为 "p" 的本机 ("raw") 指针成员变量。重载 == operator 测试 p 与正在比较的本机指针类型。 CComPtr 上名为 CoCreateInstance 的方法简单地断言它包含的原始指针已经为空,然后尝试使用原始指针作为 "out" 参数执行本机 CoCreateInstance 调用。

智能指针很棒,非常适合 COM 编程。 CComPtr 的析构函数会自动适当地在底层原始指针上调用 "Release"。如果使用得当,您将避免常见的引用计数问题,而无需考虑 "AddRef" 和 "Release".