C ++从代码中的不同位置抛出相同的错误消息

时间:2016-09-22 13:02:18

标签: c++ string exception exception-handling

我想从不同的地方抛出相同的错误。 这是一个例子:

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抛出异常时,我希望在抛出异常的地方获得相同的消息。

修改 我在想两个选择:

  1. 对于我可能抛出的每个异常,我将定义自己的类,它将继承std::exception。我可以在Exceptions.cpp
  2. 中添加每个例外
  3. 我可以定义一个将继承class MyException的{​​{1}},在构造函数中我将请求一个错误字符串。我可以在某处(我仍然无法想到放置它们的位置)定义将描述消息的静态字符串常量。例如,如果我已经定义std::exception,我可以像这样使用它:

    MyException
  4. int devide(int a,int b) { if(b==0) { throw new MyException(MyException::DEVISION_BY_ZERO); } } 将是一个字符串常量。

    我认为第二种方法需要较少的编码,但对我来说似乎并不是很好。

    那么是否有比上述两个更好的方法?

3 个答案:

答案 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 = "");

另请参阅:https://softwareengineering.stackexchange.com/questions/278949/why-do-many-exception-messages-not-contain-useful-details