我该如何处理断言失败
how should I deal with assert failure?
在调试/发布模式下,是否有正确或可接受的方法来处理断言失败?
例如:假设我有一个函数,它返回std::vector
我期望返回向量的长度等于另一个对象的长度,我这样做:
std::vector<int> v = get_stuff();
ASSERT(v.size() == this->size() )
a = v[this->size() - 1 ];
现在,如果没有触发断言,这段代码将正常工作,在调试中,这可能会崩溃,但至少断言失败会警告我出了问题。问题是在释放模式下,会出现无声的崩溃。这是否意味着我还必须检查发布代码中的这个错误,然后进行处理?这是可能的,但我认为在它上面添加断言失败没有意义,因为它是由处理的
assert
的含义与您想象的不同。它不能代替异常,我认为这就是你对它的看法。它在那里,这样你就可以在调试的早期发现问题。如果您在调试中得到断言,则修复它,然后进行测试。然后再次测试。并确保这种情况会持续下去。如果是。。。好吧,你有个bug。
这是否意味着我还必须检查发布代码中的这个错误,然后进行处理?
如果你期望它发生,是的。检查条件,抛出异常,并谨慎处理。发送错误报告。写入日志文件。更新软件。
断言适用于必须始终为true的条件。不用于异常处理。
它们反映了您在设计过程中所做的假设。如果get_stuff
返回错误大小的向量存在任何合法的可能性,则必须单独处理。
您不局限于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倍,你的测试工作也会增加。因此,在处理的地方和处理的程度上要有选择性。简单的断言和堆芯倾倒等相对简单:一个没有测试用例的内衬,可以更自由地使用。
我的偏好是包括ASSERT(用于调试),然后是处理错误的代码。在调试运行中,断言失败会使系统停止,并让我立即看到问题。然后在发布版本中,处理错误情况的代码仍然运行。当然,处理错误的代码必须经过深思熟虑。生成一个崩溃转储文件(在Windows中为小型转储,在Linux中为核心转储)可能是有意义的。
通常你必须"处理"程序中的三种错误,我个人更喜欢用以下方式(ymmv)处理和分类它们:
- 预计会频繁发生的错误(例如用户输入错误)。它们可能是(部分)可回收的。我通常通过检查/错误代码来处理它们,偶尔也会通过异常来处理
- 检测到的异常错误,但通常不会出现。我总是对它们使用异常,它们通常会使操作在更大范围内失败
- 可能不会发生的错误;这是"不可能"发生的。就像在向量类中一样,您希望人们使用适当的索引。您不想在发布模式下花费宝贵的周期来检查这些条件,但当很容易检测到这些情况时,请在调试模式下进行检查,以提供更好的替代方案来应对难以调试的崩溃(例如,使用
assert(condition && "explanation of why you asser the condition here and what it means that it is violated")
)
我通常测试带有断言的函数的先决条件,例如一些指针不是null,或者值在范围内。我大量地散布它们,以便在调试模式下(我所有的测试和单元测试都在其中运行)可以发现这些错误。这有点像一些标准库所具有的"检测未定义行为"模式。
- 警告处理为错误这里有什么问题
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 使用流处理接收到的数据
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 基于多个条件处理地图中的所有元素
- 如何用数字处理log(0)
- SSL上的`curl_easy_send`和`curl_asy_recv`:如何处理`CURLE_AGAIN`
- 错误处理.将系统错误代码映射到泛型
- 从文本文件中读取时钟时间和事件时间并进行处理
- 在运行时处理类型擦除的数据-如何不重新发明轮子
- 在for循环中使用auto vs decltype(vec.size())来处理字符串的向量
- 处理ConstexPR函数中的致命错误(或断言)
- 错误 opencv 错误断言失败 (p [-1] <= 2) 是什么意思以及如何处理它?
- 如何处理python导入模块中c++断言导致的Celery WorkerLostError
- switch()中未处理的枚举类值-异常或断言
- 我该如何处理断言失败
- 编译时断言,当并非所有枚举值都在 C++ 的 switch 语句中处理时