我是否必须在CComPtr对象上调用Release()方法?

时间:2012-04-16 18:51:47

标签: windows com atl smart-pointers sapi

我正在使用SAPI5 API来处理文本到语音。如果我简化我的代码看起来像这样(我删除了错误检查以尽可能简化它):

int main() {
    CoInitialize(NULL);
    CComPtr<ISpVoice> spVoice;
    spVoice.CoCreateInstance(CLSID_SpVoice);
    ...
    CoUninitialize();
    return 0;
}

由于一些奇怪的原因,如果我不调用spVoice.Release(),我的代码会崩溃。所以上面的代码崩溃了,但是这段代码很好用:

int main() {
    CoInitialize(NULL);
    CComPtr<ISpVoice> spVoice;
    spVoice.CoCreateInstance(CLSID_SpVoice);
    ...
    spVoice.Release();
    CoUninitialize();
    return 0;
}

CComPtr不会自动释放底层对象,因为它超出了范围?

我查看了CComPtr的实现,它确实在析构函数本身中调用了Release

所以我想知道出了什么问题,为什么我自己打电话给Release,我的代码不会崩溃。但是如果我不打电话给Release那么它会崩溃。

2 个答案:

答案 0 :(得分:8)

CComPtr的析构函数将调用Release。但是,当对象超出范围时,它会这样做。在上面的代码中,这是在主要返回之前,调用CoUninitialize之后。

以下代码更正确,并保证析构函数在CoUninitialize之前运行。

int main() {
    CoInitialize(NULL);
    { // Begin scope
        CComPtr<ISpVoice> spVoice;
        spVoice.CoCreateInstance(CLSID_SpVoice);
        ...
    } / End scope, spVoice's destructor runs.
    CoUninitialize();
    return 0;
}

另一种方法是在CoInitialize / CoUninitialize周围创建一个RAII包装器。如果在spVoice之前声明了这个新对象,它的析构函数将在spVoice的析构函数之后运行,保证正确的顺序。

答案 1 :(得分:-1)

你是对的,你不能调用Release。这是在析构函数中自动完成的。 崩溃的一个原因可能是副作用,因为您没有在程序开始时初始化COM公寓。