1

是否有正确或可接受的方式来处理调试/发布模式下的断言失败?

例如:假设我有一个返回 std::vector 的函数

我希望返回向量的长度等于另一个对象的长度,我这样做:

std::vector<int> v = get_stuff();
ASSERT(v.size() == this->size() )
a = v[this->size() - 1 ];

现在,如果没有触发断言,此代码将正常工作,并且在调试中这可能会崩溃,但至少我会有断言失败警告我有问题。问题出在发布模式下,会出现无声崩溃。这是否意味着我还必须在发布代码中检查此错误,然后进行处理?这是可能的,但是我认为在它上面添加断言失败没有意义,因为它已被处理

4

5 回答 5

2

Anassert的含义与您似乎认为的不同。它不能替代例外,我认为这是您的想法。它在那里,以便您可以在调试的早期发现问题。如果你在调试中得到断言,你就修复它。然后你测试。然后再次测试。并确保条件在释放时保持不变。如果确实如此......那么,你有一个错误。

这是否意味着我还必须在发布代码中检查此错误,然后进行处理?

如果你期望它发生,是的。检查条件,抛出异常,并巧妙处理。发送错误报告。写入日志文件。更新软件。

于 2012-08-21T21:53:59.323 回答
1

断言适用于必须始终为真的条件。不适用于异常处理。

它们反映了您在设计期间所做的假设。如果有任何合法的可能性get_stuff返回错误大小的向量,您必须单独处理。

于 2012-08-21T22:00:07.677 回答
1

您不仅限于 C 库提供的断言,还可以有一个额外的断言机制,该机制仍在生产/发布版本中运行:

  • 使用 C 库assert进行昂贵的(CPU、高速缓存、数据库负载...)检查,您不想减慢生产/发布构建的速度
  • 使用您自己的断言机制来执行您想要在生产/发布版本中运行的廉价或极其重要的测试,其中失败表明您的程序不能被信任在此后正常运行:例如,如果一个数据结构是您的程序的核心操作明显损坏
  • 当您认为可以报告错误并恢复到有用状态以进行进一步工作时,请使用异常/错误代码等,并且优先考虑继续提供该服务

因此,在您的示例中:

std::vector<int> v = get_stuff();
ASSERT(v.size() == this->size());
a = v[this->size() - 1];

您可以使用仅调试模式的 ASSERT,也可以在生产中使用的 ASSERT,或者按照前者...

a = v.at(this->size() - 1);

...这样您就可以在生产中出现问题时捕获并处理异常。要获得异常处理案例的代码覆盖率,您需要为生产构建创建一个单元测试案例。

需要记住的是找到一个现实且可维护的平衡点:如果您试图在运行时错误处理中过于详尽,您的代码可能会膨胀到 5 或 10 倍的大小和复杂性,以及您的测试工作量。所以在你处理的地方和程度上要有选择性。简单的断言和核心转储等相对简单:一个没有测试用例的单行,并且可以更自由地使用。

于 2012-08-21T23:29:24.373 回答
0

我的偏好是包含 ASSERT(用于调试),后跟处理错误的代码。在调试运行中,断言失败使系统停止运行,让我立即看到问题。然后在发布版本中,处理错误情况的代码仍然运行。当然,必须考虑处理错误的代码。生成故障转储文件(Windows 中的 minidump,Linux 中的核心转储)可能是有意义的。

于 2012-08-21T21:54:45.407 回答
0

通常你必须在你的程序中“处理”三种错误,我个人更喜欢用以下方式来处理和分类它们(ymmv):

  • 预期会经常发生的错误(例如错误的用户输入)。它们可能(部分)可恢复。我通常通过检查/错误代码处理它们,偶尔通过异常处理。
  • 检测到但通常不是预期的异常错误。我总是为它们使用异常,它们通常会使操作在更大范围内失败。
  • 可能不会发生的错误;这是“不可能”发生的。就像在您的向量类中一样,您希望人们使用适当的索引。您不想花费宝贵的周期在发布模式下检查这些条件,但是当很容易检测到这些情况时,请在调试模式下进行,以便为难以调试的崩溃提供更好的替代方案(例如,通过使用assert(condition && "explanation of why you asser the condition here and what it means that it is violated").

我通常使用断言测试函数的先决条件,例如某些指针是非空的,或者值在范围内。我慷慨地将它们洒在周围,以便在调试模式下(我所有的测试和单元测试都在其中运行)可以找到这些错误。这有点像一些标准库所拥有的“检测未定义行为”模式。

于 2012-08-21T22:04:46.467 回答