以下代码正确释放所有内容,但看起来很糟糕。我怎么能编写不泄漏引用并且可读的COM代码?
忽略C ++ \ CLI位。
IBaseFilter* leftFilter;
if (graph->FindFilterByName(L"Left", &leftFilter) == S_OK)
{
IPin* leftIn;
if (leftFilter->FindPin(L"Audio Input pin (rendered)", &leftIn) == S_OK)
{
IBaseFilter* meterFilter;
if (graph->FindFilterByName(L"Meter", &meterFilter) == S_OK)
{
IPin* meterIn;
if (meterFilter->FindPin(L"Input", &meterIn) == S_OK)
{
IPin* meterOut;
if (meterFilter->FindPin(L"Output", &meterOut) == S_OK)
{
try
{
IntPtr fileName = Marshal::StringToCoTaskMemUni(source->OriginalString);
IBaseFilter* sourceFilter;
if (graph->AddSourceFilter((LPCWSTR)(void*)fileName, L"Source", &sourceFilter) == S_OK)
{
IPin* sourceOut;
if (sourceFilter->FindPin(L"Output", &sourceOut) == S_OK)
{
if (graph->Connect(sourceOut, meterIn) == S_OK)
{
IBaseFilter* rightFilter;
if (graph->FindFilterByName(L"Right", &rightFilter) == S_OK)
{
IPin* rightIn;
if (rightFilter->FindPin(L"Audio Input pin (rendered)", &rightIn) == S_OK)
{
IBaseFilter* splitFilter;
if (graph->FindFilterByName(L"Split", &splitFilter) == S_OK)
{
IPin* splitIn;
if (splitFilter->FindPin(L"Input", &splitIn) == S_OK)
{
IPin* splitLeft;
if (splitFilter->FindPin(L"Left", &splitLeft) == S_OK)
{
IPin* splitRight;
if (splitFilter->FindPin(L"Right", &splitRight) == S_OK)
{
if (graph->ConnectDirect(meterOut, splitIn, NULL) == S_OK
&& graph->ConnectDirect(splitLeft, leftIn, NULL) == S_OK
&& graph->ConnectDirect(splitRight, rightIn, NULL) == S_OK)
{
this->source = source;
OnMediaOpened(EventArgs::Empty);
}
splitRight->Release();
}
splitLeft->Release();
}
splitIn->Release();
}
splitFilter->Release();
}
rightIn->Release();
}
rightFilter->Release();
}
else
{
if (graph->ConnectDirect(meterOut, leftIn, NULL) == S_OK)
{
this->source = source;
OnMediaOpened(EventArgs::Empty);
}
}
}
sourceOut->Release();
}
sourceFilter->Release();
}
Marshal::FreeCoTaskMem(fileName);
}
catch (Exception^) { }
meterOut->Release();
}
meterIn->Release();
}
meterFilter->Release();
}
leftIn->Release();
}
leftFilter->Release();
}
答案 0 :(得分:2)
使用智能指针,例如CComPtr。 MSDN documentation on CComPtr有一个示例,说明与手动生命周期管理相比,CComPtr如何使事情变得更容易。
答案 1 :(得分:2)
使用智能指针查看所有Release()
,然后使用失败,而不是成功,作为条件。
if (graph->FindFilterByName(L"Left", &leftFilter) != S_OK)
throw ...;
当然,这可以重构为您最喜欢的内联函数或宏。
答案 2 :(得分:1)
您可以使用某种智能指针,它将在析构函数中为您调用Release。例如,CComPtr或Boost的intrusive pointer。
答案 3 :(得分:0)
使用boost::intrusive_ptr
可以将所有这些来电转移到Release
。我想不出另一种方法来删除所有嵌套的if
,但是让函数抛出异常。考虑使用检查S_OK
或throw
s。