我正在使用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
那么它会崩溃。
答案 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公寓。