[英]C++ Throwing same error message from different places in code
我想从不同的地方抛出相同的错误。 这是一个例子:
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
抛出一个devisor to be different from 0
的异常时,我希望在抛出异常的地方获得相同的消息。
编辑:我在想两个选择:
std::exception
。 我可以在Exceptions.cpp
每个Exceptions.cpp
。 我可以定义一个将继承std::exception
class MyException
,在构造函数中我将请求一个错误字符串。 我可以在某处(我仍然无法想到放置它们的位置)定义将描述消息的静态字符串常量。 例如,如果我已经定义了MyException
我可以像这样使用它:
int devide(int a,int b) { if(b==0) { throw new MyException(MyException::DEVISION_BY_ZERO); } }
其中MyException::DEVISION_BY_ZERO
将是一个字符串常量。
我认为第二种方法需要较少的编码,但对我来说似乎并不是很好。
那么有比上面两个更好的方法吗?
将原始类型作为异常抛出并不是一个好主意。 最好的方法是使用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
。
你能做的最好的事情是创建自己的异常并抛出它。
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 );
这样就可以在一个地方处理所有未捕获的异常。
其他人所说的不抛出原始类型,使用适当的异常类,从std::exception
派生......都是好的和正确的。
让我们在这里关注你的“真实”问题:
假设我有100种不同类型的异常,但是当我为devisor抛出一个与0不同的异常时,我希望在抛出异常的地方获得相同的消息。
给定正确类型的异常,这是你想要的,你肯定不希望到处都有相同的异常消息。
让我们从答案中看一下这个例子:
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捕获所有信息并根据您的std::exception
派生类的virtual what()
方法请求格式化:
转述:
DivByZeroError(std::string const& function, std::string const& file, size_t line, optional<int> dividendValue = none, std::string const& message = "");
另见: https : //softwareengineering.stackexchange.com/questions/278949/why-do-many-exception-messages-not-contain-useful-details
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.