为了解决所有这三个问题,我发现对我来说最好的方法是抛出我自己的自定义异常,该异常源自std::runtime_error
. 像这样:
#include <exception>
class ChrisAException : public std::runtime_error
{
/// constructor only which passes message to base class
ChrisAException(std::string msg)
: std::runtime_error(msg)
{
}
}
它允许接受一个字符串,我总是把它放在下面的格式中(假设x
否定不是一个有效的输入并且意味着调用它的东西是错误的):
#include "ChrisAException.h"
void myfunction(int x)
{
if(x < 0)
{
throw ChrisAException("myfunction(): input was negative!");
}
// rest of your function
}
对于这一点,请记住,这些异常中的字符串更多的是为程序员而不是最终用户。当出现故障时,界面的程序员的工作是在语言环境中显示一些有意义的东西。异常中的字符串可以在调试时记录或查看(最好!)
这样,您最终可以通过以下方式捕获它:
try
{
// high level code ultimately calling myfunction
}
catch(ChrisAException &cae)
{
// then log cae.what()
}
catch(std::runtime_error &e)
{
// this will also catch ChrisAException's if the above block wasn't there
}
catch(...)
{
// caught something unknown
}
我个人不喜欢派生太多类型的异常,或者给出错误代码。我让字符串消息进行报告。
通常,我使用 C++ 异常来表示“程序出了问题”,而不是处理正常的用例。因此,对我来说,算法执行期间抛出的异常要么意味着“标记用户出现问题”或“不告诉用户”(取决于代码对他们所做的事情的重要性),但肯定会记录它并以某种方式让程序员知道。
我不使用 C++ 异常来处理本质上不是编程错误的情况,例如,某种不正确的逻辑或被称为错误的东西。例如,我不会使用 C++ 异常来处理正常的程序情况,例如空 DVD 不在 DVD 写入程序的驱动器中。为此,我有明确的返回码,允许用户知道是否有空 DVD(可能带有对话框等)
请记住,C++ 异常处理的一部分是将堆栈展开为一个try-catch
块。对我来说,这意味着中止程序中正在发生的事情并清理堆栈。对于像我的 DVD 示例这样的情况,您不应该真的想展开很多堆栈。这不是灾难性的。您应该简单地让用户知道,然后让他们再试一次。
但同样,这是我使用 C++ 异常的首选方式,基于经验和我的阅读。我对其他意见持开放态度。
编辑:更改std::exception
为std::runtime_error
基于评论者的建议。