在 C++ 中使用 assert() 是不好的做法吗? [英] Is using assert() in C++ bad practice?

查看:49
本文介绍了在 C++ 中使用 assert() 是不好的做法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我倾向于在我的 C++ 代码中添加大量断言,以便在不影响发布版本性能的情况下更容易调试.现在,assert 是一个纯 C 宏,没有考虑 C++ 机制.

I tend to add lots of assertions to my C++ code to make debugging easier without affecting the performance of release builds. Now, assert is a pure C macro designed without C++ mechanisms in mind.

C++ 定义了std::logic_error,它意味着在程序逻辑出现错误的情况下抛出(因此得名).抛出一个实例可能是 assert 的完美的、更 C++ 风格的替代方案.

C++ on the other hand defines std::logic_error, which is meant to be thrown in cases where there is an error in the program's logic (hence the name). Throwing an instance might just be the perfect, more C++ish alternative to assert.

问题在于assertabort 都立即终止程序而不调用析构函数,因此跳过了清理,而手动抛出异常会增加不必要的运行时成本.解决这个问题的一种方法是创建一个自己的断言宏 SAFE_ASSERT,它的工作方式与 C 对应物一样,但在失败时抛出异常.

The problem is that assert and abort both terminate the program immediately without calling destructors, therefore skipping the cleanup, whereas throwing an exception manually adds unnecessary runtime costs. One way around this would creating an own assertion macro SAFE_ASSERT, which works just like the C counterpart, but throws an exception on failure.

对于这个问题我能想到三种意见:

  • 坚持 C 的断言. 由于程序立即终止,更改是否正确展开并不重要.此外,在 C++ 中使用 #defines 也同样糟糕.
  • 抛出异常并在 main() 中捕获它.允许代码在程序的任何状态下跳过析构函数都是不好的做法,必须不惜一切代价避免,调用 terminate() 也是如此.如果抛出异常,则必须捕获它们.
  • 抛出异常并让它终止程序.异常终止程序是可以的,并且由于 NDEBUG,这在发布版本中永远不会发生.捕获是不必要的,并将内部代码的实现细节暴露给 main().
  • Stick to C's assert. Since the program is terminated immediately, it does not matter whether changes are correctly unrolled. Also, using #defines in C++ is just as bad.
  • Throw an exception and catch it in main(). Allowing code to skip destructors in any state of the program is bad practice and must be avoided at all costs, and so are calls to terminate(). If exceptions are thrown, they must be caught.
  • Throw an exception and let it terminate the program. An exception terminating a program is okay, and due to NDEBUG, this will never happen in a release build. Catching is unnecessary and exposes implementation details of internal code to main().

这个问题有明确的答案吗?有专业参考吗?

Is there a definitive answer to this problem? Any professional reference?

跳过析构函数当然不是未定义的行为.

Edited: Skipping destructors is, of course, no undefined behaviour.

推荐答案

断言在 C++ 代码中完全合适.异常和其他错误处理机制与断言的目的并不相同.

Assertions are entirely appropriate in C++ code. Exceptions and other error handling mechanisms aren't really intended for the same thing as assertions.

错误处理适用于有可能向用户很好地恢复或报告错误的情况.例如,如果在尝试读取输入文件时出现错误,您可能需要对此做一些事情.错误可能由错误引起,但也可能只是给定输入的适当输出.

Error handling is for when there's a potential for recovering or reporting an error nicely to the user. For example if there's an error trying to read an input file you may want to do something about that. Errors could result from bugs, but they could also simply be the appropriate output for a given input.

断言用于检查 API 的要求是否在通常不会被检查的情况下得到满足,或者用于检查开发人员认为他通过构造保证的事情.例如,如果算法需要排序输入,您通常不会检查它,但您可能有一个断言来检查它,以便调试构建标记那种错误.断言应始终表明程序运行不正确.

Assertions are for things like checking that an API's requirements are met when the API wouldn't normally be checked, or for checking things the developer believes he's guaranteed by construction. For example if an algorithm requires sorted input you wouldn't normally check that, but you might have an assertion to check it so that debug builds flag that kind of bug. An assertion should always indicate an incorrectly operating program.

如果您正在编写一个程序,其中非正常关闭可能会导致问题,那么您可能希望避免断言.严格按照 C++ 语言的未定义行为在这里不属于此类问题,因为命中断言可能已经是未定义行为的结果,或者违反了可能阻止某些清理工作正常工作的某些其他要求.

If you're writing a program where an unclean shutdown could cause a problem then you may want to avoid assertions. Undefined behavior strictly in terms of the C++ language doesn't qualify as such a problem here, since hitting an assertion is probably already the result of undefined behavior, or the violation of some other requirement which could prevent some clean-up from working properly.

此外,如果您根据异常实现断言,则它可能会被捕获并处理",即使这与断言的目的相矛盾.

Also if you implement assertions in terms of an exception then it could potentially be caught and 'handled' even though this contradicts the very purpose of the assertion.

这篇关于在 C++ 中使用 assert() 是不好的做法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆