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

我正在使用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那么它崩溃。

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的析构函数之后运行,保证正确的顺序。

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