复杂的错误处理
我有一个特别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;
}
有了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();
}
这实质上是移动'如果(IS_OPEN)''来〜Connector'代替把它留在'connect()'函数中。其中一个优点是,如果我需要在别处打开接受器,它可以避免代码重复。在我的特殊情况下,我没有。 – 2010-04-28 16:46:31
那么,代码没有try-catch块。你没有发现这是一个优势?您要求RAI如何简化您的代码,建议可能会更简单吗? – 2010-05-01 10:04:24
这包括两个try-catch块,其价格昂贵并且不符合RAI C++习惯用法。 – 2010-05-02 18:06:54