穷尽失败的情况,将依赖上下文的语句放在if的{}中,if变得越来越深,就像下面这样
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IFileOpenDialog * iFileOpen;
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_IFileOpenDialog, (void**)&iFileOpen);
if (SUCCEEDED(hr))
{
hr = iFileOpen->Show(NULL);
if (SUCCEEDED(hr))
{
IShellItem * iItem;
hr = iFileOpen->GetResult(&iItem);
if (SUCCEEDED(hr))
{
PWSTR pszFilePath;
hr = iItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
if (SUCCEEDED(hr))
{
MessageBox(NULL, pszFilePath, L"File Path", MB_OK);
优点:
变量拥有最小的作用域,就像上面的iItem直到使用才被声明
在每个if中,不变量都变得确定,可以确保先前的调用都成功了,这样也便于资源的释放
缺点:
一些人认为这样让代码逻辑难以阅读,伴随着错误处理,简直让人崩溃
一个行为对应一个if,成功,将下一个行为放在if的{}中,然后跳出该if,新开if测试,就像这样
if (SUCCEEDED(hr))
{
hr = pFileOpen->Show(NULL);
}
if (SUCCEEDED(hr))
{
hr = pFileOpen->GetResult(&pItem);
}
if (SUCCEEDED(hr))
{
// Use pItem (not shown).
}
优点:
没有嵌套,资源释放在代码的同一个地方
缺点:
所有的代码必须声明初始化在一开始(C语言)
错误变得唔(当一个调用失败,不能立即退出函数)在循环里面错误将变得特别
Goto是一个不错的选择,尽管有许多人把goto视为洪水猛兽
if (FAILED(hr))
{
goto done;
}
hr = pFileOpen->Show(NULL);
if (FAILED(hr))
{
goto done;
}
hr = pFileOpen->GetResult(&pItem);
if (FAILED(hr))
{
goto done;
}
// Use pItem (not shown).
done:
// Clean up.
SafeRelease(&pItem);
SafeRelease(&pFileOpen);
优点:
流程清晰,一旦失败,立刻跳转,(意味着可以保证先前都是成功的)资源释放在相同的位置
缺点:
所有的变量必须声明和初始化
一些程序员厌恶goto,当然他们厌恶的理由在这里不能成立,这代码并没有调出当前函数
我十分赞同这种方式,但是 我却从未使用
try
{
CComPtr<IFileOpenDialog> pFileOpen;
throw_if_fail(CoCreateInstance(__uuidof(FileOpenDialog), NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileOpen)));
throw_if_fail(pFileOpen->Show(NULL));
CComPtr<IShellItem> pItem;
throw_if_fail(pFileOpen->GetResult(&pItem));
// Use pItem (not shown).
}
catch (_com_error err)
{
// Handle error.
}
优点:
顺便使用RAII.C++血统十足
缺点:
大部分程序员智商不够(比如我),无法写出异常安全的代码