0

当我为 Windows 编写 C 代码时,我应该“默认”使用 SEH 的__try...__finally块,还是认为不必要地这样做是不好的做法?

换句话说,下面哪一个(例如)被认为是更好的实践,为什么?

HDC hDCCompat = CreateCompatibleDC(hDC);
__try
{
    HBITMAP hBmpCompat = CreateCompatibleBitmap(hDC, ...);
    __try
    {
        SelectObject(hDCCompat, hBmpCompat);
        BitBlt(hDC, ..., hDCCompat, ...);
    }
    __finally { DeleteObject(hBmpCompat); }
}
__finally { DeleteObject(hDCCompat); }

相对

HDC hDCCompat = CreateCompatibleDC(hDC);
HBITMAP hBmpCompat = CreateCompatibleBitmap(hDC, ...);
SelectObject(hDCCompat, hBmpCompat);
BitBlt(hDC, ..., hDCCompat, ...);
DeleteObject(hBmpCompat);
DeleteObject(hDCCompat);

澄清

我忘了提:

我的想法是,如果有人稍后在块中插入更多代码(例如,从函数中提前返回),我的代码仍然会执行清理,而不是过早退出。所以它应该比其他任何东西都更具预防性。我仍然应该避免使用 SEH 吗?

4

3 回答 3

3

在我看来,没有。缺点是有很多额外__try/__finally噪音,我看不出有什么好处。

SelectObject(hDCCompat, hBmpCompat);
BitBlt(hDC, ..., hDCCompat, ...);

你怎么期望这些失败?例如,通过返回(您不检查)而不是通过引发 SEH 异常来SelectObject报告错误。NULL许多 SEH 异常实例表明存在不可恢复的基本错误(您的内存已损坏或您犯了逻辑错误,例如将无效句柄传递给函数或其他东西)。这些类型的错误不能被优雅地处理,并且崩溃通常更容易调试。

如果你想让你的代码在面对早期返回时保持健壮(许多 C 编码标准不鼓励,部分原因是这个原因),那么你应该考虑以一种更难以以危险方式修改的方式来构建你的代码。例如

int f()
{
    int ret;
    Resource r;

    if (!AcquireResource(&r))
        return FAIL;

    ret = FunctionWithLogicAndEarlyReturns(&r);

    CleanupResource(&r);
    return ret;
}

你可以希望,因为这个函数很简单,所以不会有额外的提前返回的诱惑,被调用的“逻辑”函数中的提前返回不会损害对获取资源的清理。

于 2012-02-04T23:07:01.500 回答
1

我不会使用你的任何一个例子。我不会使用 SEH,我会检查函数的返回值。

您也未能保存和恢复 'hDCCompat 的原始位图。

于 2012-02-04T23:03:36.307 回答
1

如果此类代码引发异常,则系统可能处于这样一种状态,即您是否正确释放资源或根本不能(或两者兼而有之)都无关紧要。我个人不会使用这些,它们只会增加噪音并使您的代码看起来很奇怪。MSDN 示例也不使用它们(仅在讨论 SEH 的地方)。此外,WINAPI 中的错误处理基于返回值和输出参数。

关于您的更新:在这种情况下,我坚信 YAGNI 适用。当然,这取决于具体的应用程序,如果您事先知道会有需要SEH 的代码,那么它可能是有意义的。否则,没有那么多。实际需要时添加异常处理。

于 2012-02-04T23:11:50.410 回答