还原C++流式呼叫者的异常蒙版
我正在编写一个C ++函数,该功能以std :: istream
为参数,并从中读取以解码图像。解码图像时,如果在阅读过程中出现某些错误,我希望流进行异常。这样,我就不必用我的解码逻辑的其余部分插入错误标志,从而使我的代码变得更加简单。
由于呼叫者可能会通过流启用流,因此我的功能将启用它们。当功能退出时,我想还原流的初始异常蒙版。我只是在学习C ++,并试图将我的头缠绕在处理这样的情况的惯用方式上 - 我通常会在最后将清理代码扔进
终于块:
Image::Image(std::istream& stream) {
std::ios_base::iostate originalExceptionSettings = stream.exceptions();
try {
// Enable exceptions.
stream.exceptions(
std::ios_base::badbit |
std::ios_base::failbit |
std::ios_base::eofbit);
// Do some stuff that might cause stream to throw...
}
finally { // If only!
// Restore settings that the caller expects.
stream.exceptions(originalExceptionSettings);
}
}
我已经看到人们说<代码>最后,应像RAII一样处理 -Type清理代码。我想我可以创建一个小班来包装这一责任,从而节省了指向流的指针和原始异常面具。它的破坏者将将原始异常面膜恢复到流中。
// Something like this...
StreamExceptionMaskMemo::StreamExceptionMaskMemo(std::istream* stream)
{
this->originalExceptionSettings = stream->exceptions();
this->stream = stream;
}
StreamExceptionMaskMemo::~StreamExceptionMaskMemo()
{
// Could throw!
this->stream->exceptions(this->originalExceptionSettings);
}
虽然在我的情况下这将有效,但使用此类存储一个异常掩码,该类别应抛出,以便在 disables exceptions中使用。如果使用该类别,则可以重新确定异常,这立即引发了当前状态所暗示的任何例外。
我意识到这有点人为 - 也许呼叫者不再使用混乱的流 - 但是我仍然对如何解决以下问题感到困惑:
- 我如何编写使用呼叫者提供的流的代码,知道该流可以完全不同的行为,具体取决于例外面具是什么?
- 您如何编写可以投掷的清理代码?如果我使用的是
最后
,我可以在终于
block中捕获一个异常,然后做适当的事情。但是,如果我要把清理责任拆分到另一个班级以允许RAII,我必须让它的destuructor抛出例外,或者吞下它们。
I am writing a C++ function that takes a std::istream
as an argument and reads from it to decode an image. When decoding the image, I want the stream to throw exceptions if some error occurs during reading. That way, I don't have to intersperse checking the error flags with the rest of my decoding logic, making my code simpler.
Because the caller might pass a stream without exceptions enabled, my function will enable them. I would like to restore the stream's initial exception mask when the function exits. I am just learning C++ and am trying to wrap my head around the idiomatic way to handle situations like this - where I'd normally toss cleanup code in a finally
block:
Image::Image(std::istream& stream) {
std::ios_base::iostate originalExceptionSettings = stream.exceptions();
try {
// Enable exceptions.
stream.exceptions(
std::ios_base::badbit |
std::ios_base::failbit |
std::ios_base::eofbit);
// Do some stuff that might cause stream to throw...
}
finally { // If only!
// Restore settings that the caller expects.
stream.exceptions(originalExceptionSettings);
}
}
I've seen people say that finally
-type cleanup code should be handled like RAII. I guess I could create a little class to wrap this responsibility, which saves a pointer to the stream and the original exception mask. Its destructor would restore the original exception mask to the stream.
// Something like this...
StreamExceptionMaskMemo::StreamExceptionMaskMemo(std::istream* stream)
{
this->originalExceptionSettings = stream->exceptions();
this->stream = stream;
}
StreamExceptionMaskMemo::~StreamExceptionMaskMemo()
{
// Could throw!
this->stream->exceptions(this->originalExceptionSettings);
}
While that will work in my case, it would be problematic to use this class to store an exception mask that specifies exceptions should be thrown for use in a function that disables exceptions. If the class was used that way, the destructor would reenable the exceptions, which immediately throws whatever exceptions are implied by the current state.
I realize this is a bit contrived - probably the caller won't use a messed up stream anymore - but I am still confused about how I'd address the following problems:
- How do I write code that uses a stream supplied by a caller, knowing that the stream could have totally different behavior depending on what the exception mask is?
- How do you write cleanup code that could throw? If I was using a
finally
I could catch an exception thrown from within in thefinally
block and do something appropriate. But if I am spinning off the responsibility for cleanup to another class to allow RAII, I have to either let its destructor throw exceptions, or swallow them.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果呼叫者不想要流异常,则旧面具将无法启用异常,因此旧面具的恢复不会抛出任何例外。没问题。
如果呼叫者 die 想要流异常,则如果流状态匹配呼叫者想要的例外,则修复将引发异常。再次,这不是问题。
因此,唯一真正的问题是可能会从RAII灾难内抛出例外,这通常非常糟糕(但是可以完成 a>小心)。
在这种情况下,我建议不要使用RAII。一个简单的
尝试/捕获
就足够了(尝试/最后
是不动的),例如:If the caller doesn't want stream exceptions, the old mask will not enable exceptions, so the restoration of the old mask will not throw any exception. Not a problem.
If the caller does want stream exceptions, then the restoration will throw an exception if the stream state matches what the caller wants an exception for. Again, not a problem.
So, the only real problem is the possibility of throwing an exception from inside an RAII destructor, which is generally very bad (but can be done with care).
In this case, I would suggest just not using RAII. A simple
try/catch
will suffice (try/finally
is not portable), eg: