如何在C ++

时间:2015-04-27 21:59:57

标签: c++ exception

我从C#转到C ++,请原谅我,如果问题是基本的或有一些误解......

我想构建自己的异常,以便在我的try / catch块上使用。我需要报告自定义异常代码,自定义异常消息和自定义异常源 - 我可能拥有所有或部分参数。

所以我建了那个班:

CommonException.hpp

namespace exceptionhelper
{

    class CommonException : public std::exception {

    public:
        CommonException();
        CommonException(std::string message);
        CommonException(std::string source, std::string message);
        CommonException(int code, std::string source, std::string message);
        virtual ~CommonException();
        const char *what() const throw();


    private:
        int exceptionCode;
        std::string exceptionSource;
        std::string exceptionMessage;
    };

}

实施:

CommonException.cpp

namespace exceptionhelper {
        CommonException::CommonException() {
            exceptionCode = 0;
            exceptionMessage = "No message.";
            exceptionSource = "No source.";
        }
        CommonException::CommonException(std::string message) {
            exceptionCode = 0;
            exceptionMessage = message;
            exceptionSource = "No source.";
        }
        CommonException::CommonException(std::string source, std::string message) {
            exceptionCode = 0;
            exceptionMessage = message;
            exceptionSource = source;
        }
        CommonException::CommonException(int code, std::string source, std::string message) {
            exceptionCode = code;
            exceptionMessage = message;
            exceptionSource = source;
        }
        CommonException::~CommonException() {
        }
        const char *CommonException::what() const throw()
        {
            std::stringstream s;
            s << "Code    : " << exceptionCode << std::endl;
            s << "Source  : " << exceptionSource << std::endl;
            s << "Message : " << exceptionMessage << std::endl;
            return s.str().c_str();
        }
    }

最后我的实施:

main ()
{
   try {
        ... code ...

        throw new CommonException(10, "here", "test exception");

   }
   catch (const std::exception &exc)
   {
            std::cerr << "Exception detected:" << std::endl;
            std::cerr << exc.what();
        }
        catch (...)
        {
            std::cerr << "Unknown exception called." << std::endl;
            throw;
        }
}

出于某种原因,我得到了这个结果:

Unknown exception called.
terminate called after throwing an instance of 'linuxcommon::exceptionhelper::CommonException*'
Aborted (core dumped)

问题:

a)为什么我没有捕获自定义异常? b)我很确定有更好的方法来进行这种异常处理,但我还不知道这个......

感谢您的帮助...

1 个答案:

答案 0 :(得分:3)

您的代码的一些注释。

  1. 您可能希望从std::runtime_error(而不是std::exception)派生您的异常类,因为std::runtime_error已经为构造函数提供了错误消息字符串。 当然,您可以将自己的异常数据成员添加到派生类中。

  2. 您不需要为异常类定义具有空主体的虚拟析构函数,因为您没有要执行的显式清理代码。 std::exception有一个虚拟析构函数,对于派生的异常类,它可以正常工作。

  3. 您可以使用更惯用的C ++语法来初始化构造函数中的异常数据成员,例如而不是:

  4. CommonException::CommonException() {
        exceptionCode = 0;
        exceptionMessage = "No message.";
        exceptionSource = "No source.";
    }
    

    你可以使用:

    CommonException::CommonException()
      : exceptionCode(0), 
        exceptionMessage("No message."), 
        exceptionSource("No source.")
    { }
    
    1. 如果您传递字符串参数,您仍然可以按值传递,但您可能希望从该值std::move()初始化数据成员,例如而不是:
    2. CommonException::CommonException(std::string source, std::string message) {
          exceptionCode = 0;
          exceptionMessage = message;
          exceptionSource = source;
      }
      

      你可以这样做:

      CommonException::CommonException(std::string source, std::string message) 
          : exceptionCode(0),
            exceptionMessage(std::move(message)),
            exceptionSource(std::move(source))
      {
      }
      
      1. 考虑创建单字符串参数构造函数explicit,以防止从字符串到异常的伪隐式转换:

        explicit CommonException(std::string message);
        
      2. 在当前形式中,您的what()方法实现可以抛出,因为在<<上插入操作(std::stringstream)可能会抛出:

      3. const char *CommonException::what() const throw()
        {
            std::stringstream s;
            s << "Code    : " + exceptionCode << std::endl;
            s << "Source  : " + exceptionSource << std::endl;
            s << "Message : " + exceptionMessage << std::endl;
            return s.str().c_str();
        }
        

        所以,删除throw()规范,简单地说:

        const char* CommonException::what() const
        

        (作为旁注,现代C ++ 11将方法标记为非抛出的方法是使用noexcept)。

        您可能还想简单地使用'\n'代替std::endl,以避免过早的悲观情绪。

        此外,您将在此行返回临时字符串:

         return s.str().c_str();
        

        返回给调用者的const char*指针只会指向调用站点的一些垃圾:这会引入一个错误。

        要解决此问题,您可能需要考虑添加std::string数据成员,在异常对象构造期间格式化该数据成员内的整个错误消息字符串(即在您的构造函数中 - 您还可以构建一个私有帮助器方法要做到这一点,以避免在每个构造函数中重复代码),只需从m_str.c_str()方法返回what()

        如果从std::runtime_error派生异常类,则可以在构造时构建整个错误消息字符串,并将其传递给std::runtime_error的构造函数。在这种情况下,std::runtime_error::what()将执行正确的操作,您无需在异常类中覆盖what()

        E.g。

        // Derive from std::runtime_error instead of std::exception
        class CommonException : public std::runtime_error
        
        ...
        
        CommonException::CommonException( /* your exception data */ )
            : std::runtime_error(BuildErrorMessage( /* your exception data */ )
        { }
        
        // Private helper method
        std::string CommonException::BuildErrorMessage( /* your exception data */ )
        {
            // Build your exception message string here,
            // e.g. you can use std::ostringstream here,
            // and just call its str() method
            // to return the whole error message string.
            ...
        }
        

        在例外的“客户”方面,您有:

          ... code ...
        
            throw new CommonException(10, "here", "test exception");
        
        }
        catch (const std::exception &exc)
        

        相反,请考虑按值抛出,而不是在堆上动态分配异常对象,例如只需这样做:

        throw CommonException( /* your exception data*/ );