是否有正确或可接受的方式来处理调试/释放模式中的断言失败?
例如: 假设我有一个返回std :: vector
的函数我希望返回的向量的长度等于另一个对象的长度,我这样做:
std::vector<int> v = get_stuff();
ASSERT(v.size() == this->size() )
a = v[this->size() - 1 ];
现在如果没有触发断言,这段代码将正常工作,并且在调试中这可能会崩溃,但至少我会让断言失败警告我出错了。 问题是在发布模式下,会发生无声崩溃。 这是否意味着我还必须在发布代码中检查此错误然后处理它?它是可能的,但是我认为在它上面添加一个断言失败是没有意义的,因为它已被处理
答案 0 :(得分:2)
assert
的含义与您的想法不同。它不是一个例外的替代品,我认为这是你如何看待的。它就在那里,你可以在调试的早期发现问题。如果在调试中获得断言,则修复它。然后你测试。然后再次测试。并确保条件在释放时保持不变。如果确实......好吧,你有一个错误。
这是否意味着我还必须在发布代码中检查此错误然后处理它?
如果您希望它发生,是的。检查条件,抛出异常并精细处理。发送错误报告。写入日志文件。更新软件。
答案 1 :(得分:1)
断言是指必须始终为真的条件。不适用于异常处理。
它们反映了您在设计过程中所做的假设。如果get_stuff
有任何合法的可能返回错误大小的向量,则必须单独处理。
答案 2 :(得分:1)
您不仅限于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倍,而你的测试工作也会耗尽。因此,要选择处理的地方和程度。简单地断言和核心倾倒等相对简单:一个没有测试用例的衬里,可以更自由地使用。
答案 3 :(得分:0)
我的首选是包含ASSERT(用于调试),然后是处理错误的代码。在调试运行中,断言失败会使系统停止并让我立即看到问题。然后在发布版本中,处理错误情况的代码仍然运行。当然,必须考虑处理错误的代码。生成崩溃转储文件(Windows中的minidump,Linux中的核心转储)可能是有意义的。
答案 4 :(得分:0)
通常你必须在你的程序中“处理”三种错误,我个人更喜欢按照以下方式处理和分类它们(ymmv):
我通常使用断言测试前提条件,例如某些指针非空,或者值在范围内。我慷慨地撒了它们,所以在调试模式下(我的所有测试和单元测试都在运行中)可以找到这些错误。它有点像“检测未定义行为”模式,相当一些标准库有。