这种异常处理方式是否良好?

时间:2011-05-05 12:17:07

标签: c++ exception exception-handling

你会改变这段代码中的任何内容吗?

class LocalPort {
public:
    LocalPort(int portNumber) {
      innerPort = new ACMEPort(portNumber);
   }

    void Open() {
      try {
          innerPort->Open();
      } 
      catch (DeviceResponseException& e) {
          throw PortDeviceFailure(e);
      } 
      catch (ATM1212UnlockedException& e) {
         throw PortDeviceFailure(e);
      } 
      catch (GMXError& e) {
         throw PortDeviceFailure(e);
      }
   } 
private: 
    ACMEPort* innerPort;
};

/////////

try {
    LocalPort* port = new LocalPort(12);
    port->Open();
} 
catch (bad_alloc& e) {
    ReportError(e);
    logger.Log("Wyjątek alokacji pamięci", e);
    delete port;
}
catch (PortDeviceFailure& e) {
    ReportError(e);
    logger.Log(e.getMessage(), e);
    delete port;
} 

我尝试以上做的是让代码低于看起来更好。

try {
    ACMEPort* port = new ACMEPort(12);
    port->Open();
} 
catch (bad_alloc& e) {
    ReportPortError(e);
    logger.Log("Wyjątek alokacji pamięci", e);
    delete port;
}
catch (DeviceReponseException& e) {
    ReportPortError(e);
    logger.Log("Wyjątek odpowiedzi urządzenia", e);
    delete port;
} 
catch (ATM1212UnlockedException& e) {
    ReportPortError(e);
    logger.Log("Wyjątek odblokowania", e);
    delete port;
} 
catch (GMXError& e) {
    ReportPortError(e);
    logger.Log("Wyjątek odpowiedzi urządzenia");
    delete port;
}
catch (...) {
    ReportPortError(0);
    logger.Log("Wyjątek nieznanego pochodzenia");
    delete port;
}

我成功了吗?第一个比第二个好吗?你觉得怎么样?

3 个答案:

答案 0 :(得分:7)

看起来你设计的异常类很糟糕。为什么不简单地将一个成员函数getMessage添加到您的异常层次结构中(最好是在基类中,所有异常派生自 - std::exception提供返回的方法what错误信息)。这样,您可以简单地在一个语句中捕获所有异常,并以相同的方式处理它们。

class DeviceResponseException : public std::runtime_error {
public:
    DeviceResponseException() : std::runtime_error("Some error message") {}
};

class ATM1212UnlockedException : public std::runtime_error {
public:
    ATM1212UnlockedException() : std::runtime_error("Some other error message") {}
};

然后在您的代码中,您可以执行此操作:

try {
    std::auto_ptr<ACMEPort> port(new ACMEPort(12));
    port->Open();
}
catch( std::runtime_error & e) {
    ReportPortError(e);
    logger.Log(e.what(), e);
}

由于您的异常类都派生自std::runtime_error,因此这个catch - 子句会捕获它们。这没关系,因为所有情况下的处理都是一样的。如果您有需要特殊处理的特定例外,则添加其他catch - 子句。

此外,您应该使用delete portstd::auto_ptr或类似的东西,而不是在异常处理程序中调用boost::scoped_ptr。阅读RAII

答案 1 :(得分:2)

是的,我会:

  • 有一个例外类,因此:
  • 不会将异常从一种类型转换为另一种类型
  • 在代码中捕获更高的异常,因此:
  • 最终没有写出比真实代码更多的异常处理代码
  • 我不会使用new创建对象,如果我这样做,我会使用智能指针

基本上,我认为你完全误解了应该如何使用例外。

您可以对代码进行的最佳单一更改是替换:

ACMEPort* port = new ACMEPort(12);
port->Open();

使用:

ACMEPort port(12);
port.Open();

和其他地方类似 - 捕获异常的需要随之消失。

答案 2 :(得分:0)

我将异常处理程序移到类中,让类处理错误而不是强制所有调用者处理它。这样你可以通过检查Open()的结果值来清理指针(如果你因为某些原因必须有一个指针):

class LocalPort {
public:
    LocalPort(int portNumber) {
      innerPort = new ACMEPort(portNumber);
   }

    bool Open() {
      try {
          innerPort->Open();
          return true;
      } 
      catch (DeviceResponseException& e) {
          throw PortDeviceFailure(e);
      } 
      catch (ATM1212UnlockedException& e) {
         throw PortDeviceFailure(e);
      } 
      catch (GMXError& e) {
         throw PortDeviceFailure(e);
      }
      catch (bad_alloc& e) {
         ReportError(e);
         logger.Log("Wyjątek alokacji pamięci", e);
      }
      catch (PortDeviceFailure& e) {
         ReportError(e);
         logger.Log(e.getMessage(), e);
      }
      return false;
   } 
private: 
    ACMEPort* innerPort;
};

LocalPort* port = new LocalPort(12);
if (!port->Open()) {
  delete port;
}