错误处理的四种方法

嵌套if

    穷尽失败的情况,将依赖上下文的语句放在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测试,就像这样

    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++血统十足

    缺点:

        大部分程序员智商不够(比如我),无法写出异常安全的代码

你可能感兴趣的:(方法)