繁体   English   中英

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

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

编辑:我在想两个选择:

  1. 对于我可能抛出的每个异常,我将定义自己的类,它将继承std::exception 我可以在Exceptions.cpp每个Exceptions.cpp
  2. 我可以定义一个将继承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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM