c++ - 在 C++ 中使用 assert() 是不好的做法吗?

标签 c++ coding-style assert

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

另一方面,C++ 定义了 std::logic_error,这是为了在程序逻辑中出现错误的情况下抛出(因此得名)。抛出一个实例可能只是 assert 的完美、更 C++ 的替代方案。

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

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

  • 坚持 C 的断言。 由于程序立即终止,因此更改是否正确展开并不重要。此外,在 C++ 中使用 #define 也同样糟糕。
  • 抛出一个异常并在 main() 中捕获它。允许代码在程序的任何状态下跳过析构函数是不好的做法,必须不惜一切代价避免,对 terminate() 的调用也是如此。如果抛出异常,则必须捕获它们。
  • 抛出异常并让它终止程序。异常终止程序是可以的,并且由于 NDEBUG,这在发布版本中永远不会发生。捕获是不必要的,它会将内部代码的实现细节暴露给 main()

这个问题有明确的答案吗?有什么专业的引用吗?

已编辑:跳过析构函数当然不是未定义的行为。

最佳答案

  • 断言用于调试。您的交付代码的用户不应该看到它们。如果一个断言被命中,你的代码需要被修复。

    CWE-617: Reachable Assertion

The product contains an assert() or similar statement that can be triggered by an attacker, which leads to an application exit or other behavior that is more severe than necessary.

While assertion is good for catching logic errors and reducing the chances of reaching more serious vulnerability conditions, it can still lead to a denial of service.

For example, if a server handles multiple simultaneous connections, and an assert() occurs in one single connection that causes all other connections to be dropped, this is a reachable assertion that leads to a denial of service.

  • 异常(exception)情况适用于特殊情况。如果遇到这种情况,用户将无法做她想做的事,但可以在其他地方继续。

  • 错误处理适用于正常的程序流程。例如,如果您提示用户输入数字并得到无法解析的内容,这是正常,因为用户输入不受您的控制,您必须始终理所当然地处理所有可能的情况。 (例如,循环直到你有一个有效的输入,在两者之间说“抱歉,再试一次”。)

关于c++ - 在 C++ 中使用 assert() 是不好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12062365/

相关文章:

c++ - 这是在 MSVC 2013 中使用共享 ptr 的 Singleton 的正确实现吗?

c++ - 在 Ubuntu 上编写的 C++ 软件中的僵尸窗口

Android:偏好风格

javascript - Dojo 有编码标准吗?

coding-style - 关于变量/函数命名约定的思考

c++ - itemAt 不返回自定义 qGraphicsItem

java - java异常的catch block 中是否会捕获断言错误?

java - Selenium Webdriver 断言 2 个元素在 Java 中包含相同的数字

java - 在 try/catch 中断言 True

c++ - Linux UDP 服务器 - 目标 IP 错误