我想从不同的地方抛出相同的错误。 这是一个例子:
int devide(int a,int b)
{
if(b==0) {
throw "b must be different from 0";
}
return 0;
}
int mod(int a,int b)
{
if(b==0) {
throw "b must be different than 0";
}
return 0;
}
在主要功能中:
int main()
{
try {
devide(1,0);
} catch(char const* e) {
cout << e << endl;
}
try {
mod(1,0);
} catch(char const* e) {
cout << e << endl;
}
return 0;
}
现在该程序的输出是:
b must be different from 0
b must be different than 0
如您所见,错误本质上是相同的,但错误消息是不同的。那么在这种情况下我可以遵循的最佳实践是什么,所以它可以扩展?假设我有100种不同类型的异常,但是当我为devisor to be different from 0
抛出异常时,我希望在抛出异常的地方获得相同的消息。
修改 我在想两个选择:
std::exception
。我可以在Exceptions.cpp
。我可以定义一个将继承class MyException
的{{1}},在构造函数中我将请求一个错误字符串。我可以在某处(我仍然无法想到放置它们的位置)定义将描述消息的静态字符串常量。例如,如果我已经定义std::exception
,我可以像这样使用它:
MyException
int devide(int a,int b)
{
if(b==0) {
throw new MyException(MyException::DEVISION_BY_ZERO);
}
}
将是一个字符串常量。
我认为第二种方法需要较少的编码,但对我来说似乎并不是很好。
那么是否有比上述两个更好的方法?
答案 0 :(得分:3)
将原始类型作为异常抛出并不是一个好主意。最好的方法是使用std::runtime_error
,这是针对此类情况的。
如果您想区分catch()
块中的错误,可以从该异常派生并使用特定文本进行初始化:
class DivByZeroError : public std::runtime_error {
public:
DivByZeroError() : std::runtime_error("divisor must be different from 0") {}
// Alternate constructor to provide a specific error message
DivByZeroError(const std::string& s) : std::runtime_error(s) {}
}
class ModWithZeroError : public std::runtime_error {
public:
ModWithZeroError () : std::runtime_error("divisor must be different than 0") {}
ModWithZeroError (const std::string& s) : std::runtime_error(s) {}
}
int main()
{
try {
devide(1,0);
mod(1,0);
} catch(const DivByZeroError& e) {
cout << e.what() << endl;
} catch(const ModWithZeroError & e) {
cout << e.what() << endl;
} catch(const std::exception & e) { // Any other exceptions
cout << e.what() << endl;
}
return 0;
}
正如@CaptainOblivious在评论中提到的那样,如果参数名称只是错误消息中唯一要更改的内容,那么您还可以继承std::invalid_argument
。
答案 1 :(得分:2)
你能做的最好的事情就是创建自己的异常并抛出它。
class Exception : public std::exception
{
public:
template< typename... Args >
Exception( const std::string& msg, Args... args );
virtual ~Exception() throw ();
//! Overrides std::exception
virtual const char* what() const throw();
private:
//! Log the message_
void log() const;
protected:
std::string message_;
};
template< typename... Args >
Exception::Exception( const std::string& msg, Args... args )
: message_( StrFmt::format( msg, args ... ) )
{
log();
}
class MyException : public Exception
{
MyException() : Exception( std::string("b must be different from 0") )
}
如果您计划在未捕获的异常上退出程序,则可以安装终止处理程序,在此处重新抛出异常。
static void terminate()
{
static bool tried_rethrow = false;
try
{
if ( !tried_rethrow )
{
tried_rethrow = true;
throw;
}
}
catch ( const std::runtime_error& err )
{
std::cout << err.what();
}
catch ( const Exception& err )
{
std::cout << err.what();
}
catch ( ... )
{
}
}
并在你的main.cpp中:
std::set_terminate( terminate );
这样就可以在一个地方处理所有未捕获的异常。
答案 2 :(得分:1)
其他人所说的不抛弃原始类型,使用适当的异常类,派生自std::exception
...都是好的和正确的。
让我们专注于你真实的&#34;问题在这里:
让我们说我有100种不同类型的例外,但是当我 抛出一个异常让devisor与我想要得到的不同 抛出异常的地方到处都是相同的信息。
根据你想要的正确类型的异常,你确定不希望在任何地方都有相同的异常消息。
让我们从答案中看一下这个例子:
class DivByZeroError : public std::runtime_error {
public:
DivByZeroError() : std::runtime_error("divisor must be different from 0") {}
// Alternate constructor to provide a specific error message
DivByZeroError(const std::string& s) : std::runtime_error(s) {}
}
默认构造函数确保方便易用。它也是100%多余和多余的。它是DivByZeroError
,无需再将(仅) 放入邮件中。
你真正想要的是没有拥有默认构造函数的例外,因为你总是想要详细的信息 去了什么错误其中和时。
所以,你真正想要的是一个exc。 ctor捕获所有信息并根据您what()
派生类的虚拟std::exception
方法请求格式化:
意译:
DivByZeroError(std::string const& function, std::string const& file, size_t line, optional<int> dividendValue = none, std::string const& message = "");