复杂的错误处理

时间:2010-04-28 15:37:19

标签: c++ exception exception-handling

我有一个特别令人讨厌的网络代码。我正在使用asio,但这对于这个问题并不重要。我假设除了关闭套接字之外没有办法取消绑定套接字。问题是open()bind()listen()都可以抛出system_error。所以我用一个简单的try/catch来处理代码。代码以破碎的方式写成。

using namespace boost::asio;

class Thing
{
public:

   ip::tcp::endpoint m_address;

   ip::tcp::acceptor m_acceptor;

   /// connect should handle all of its exceptions internally.
   bool connect()
   {
      try
      {
         m_acceptor.open( m_address.protocol() );
         m_acceptor.set_option( tcp::acceptor::reuse_address(true) );

         m_acceptor.bind( m_address );
         m_acceptor.listen();

         m_acceptor.async_accept( /*stuff*/ );
      }
      catch( const boost::system::system_error& error )
      {
         assert(acceptor.is_open());
         m_acceptor.close();
         return false;
      }
      return true;
   }

   /// don't call disconnect unless connect previously succeeded.
   void disconnect()
   {
      // other stuff needed to disconnect is ommited
      m_acceptor.close();
   }
};

错误是如果套接字连接失败,它将尝试在catch块中关闭它并抛出另一个关于关闭一个从未打开过的接受器的system_error。

一种解决方案是在catch块中添加if( acceptor.is_open() ),但尝试错了。有点像混合C - 样式错误检查与c++例外。如果我去哪条路线,我也可以使用open()的非投掷版本。

boost::system::error_code error;
acceptor.open( address.protocol, error );
if( ! error )
{
    try
    {
       acceptor.set_option( tcp::acceptor::reuse_address(true) );

       acceptor.bind( address );
       acceptor.listen();

       acceptor.async_accept( /*stuff*/ );
    }
    catch( const boost::system::system_error& error )
    {
       assert(acceptor.is_open());
       acceptor.close();
       return false;
    }
}
return !error;

使用RAII和try/catch块有没有一种优雅的方法来处理这些可能的异常?

在使用例外时,我是否错误地试图避免if( error condition )样式错误处理?

2 个答案:

答案 0 :(得分:3)

我建议只对open执行单独的错误处理,因为之前和之后有不同的清理:

bool connect()
{
  try {
     m_acceptor.open( m_address.protocol() );
  } catch( const boost::system::system_error& error ) {
     return false;
  }

  try {
     m_acceptor.set_option( tcp::acceptor::reuse_address(true) );

     m_acceptor.bind( m_address );
     m_acceptor.listen();

     m_acceptor.async_accept( /*stuff*/ );
  } catch( const boost::system::system_error& error ) {
     m_acceptor.close();
     return false;
  }
  return true;
}

答案 1 :(得分:2)

使用try-catch,您可以考虑到system_error有一个error_code,它给出了真正的原因。所以你可以在catch句子上测试这个error_code。

要使用RAI,您需要在构造函数上进行连接并在析构函数上进行断开连接,但我不知道

背后的内容是什么
acceptor.async_accept( /*stuff*/ );

所以也许你需要保留这一部分。 事情;

{
 Connector conn(th); / connect on constructor
 // ... th.async_accept  
 // do some work while connected
}
 // disconnect on destructor

Connector将使用在acceptor.open()成功之后设置的特定成员变量is_open来处理接受者是否打开。

   Connector::Connector(...)
   : ...
   , is_open(false)
   {
     m_acceptor.open( m_address.protocol() );
     is_open=true;
     m_acceptor.set_option( tcp::acceptor::reuse_address(true) );

     m_acceptor.bind( m_address );
     m_acceptor.listen();

     m_acceptor.async_accept( /*stuff*/ );
   }

   Connector::~Connector(...)
   {
     // other stuff needed to disconnect is omitted
     if (is_open) m_acceptor.close();
   }