复杂的错误处理

问题描述:

我有一个特别ornery一段网络代码。我正在使用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 -style错误检查与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)风格错误处理时使用异常?

我建议只是在做不同的处理错误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

这包括两个try-catch块,其价格昂贵并且不符合RAI C++习惯用法。 – 2010-05-02 18:06:54

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

要使用RAI你需要做连接的构造函数和析构函数断开,但我不知道背后是什么

acceptor.async_accept(/*stuff*/); 

所以也许你需要让出这部分。 Thing th;

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

连接器将采取的受体是否打开或不使用特定的成员变量只是在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(); 
    } 
+0

这实质上是移动'如果(IS_OPEN)''来〜Connector'代替把它留在'connect()'函数中。其中一个优点是,如果我需要在别处打开接受器,它可以避免代码重复。在我的特殊情况下,我没有。 – 2010-04-28 16:46:31

+1

那么,代码没有try-catch块。你没有发现这是一个优势?您要求RAI如何简化您的代码,建议可能会更简单吗? – 2010-05-01 10:04:24