考虑以下简单的streambuf实现:
#include <iostream>
#include <sstream>
class mystreambuf : public std::streambuf
{
int_type underflow() override
{
throw std::runtime_error("here");
}
};
int main()
{
mystreambuf rdbuf;
std::ostringstream os;
std::cout << "State: " << os.exceptions() << std::endl;
try
{
os << &rdbuf;
std::cout << "No except: " << os.good() << std::endl;
}
catch (std::runtime_error const&)
{
std::cout << "With except: " << os.good() << std::endl;
}
return 0;
}
上面的实现似乎是遵循我对另一篇文章的理解:
但是我看到了不同的行为。使用 gcc/linux 我得到:
State: 0
No except: 0
在 Visual Studio 2019 上我得到:
State: 0
With except: 0
哪种行为是正确的?两者都?
供参考:
在这样的情况下,你真正应该扔的是类
std::ios_base::failure
的对象,或者从它派生的其他类。
当/如果你这样做:
class mystreambuf : public std::streambuf
{
int_type underflow() override
{
throw std::ios_base::failure("here");
}
};
// remainder as in question
...g++ 与 MS VC++ 具有相同的行为:
State: 0
No except: 0
对我来说,真正的意图似乎很清楚,您抛出的异常是
std::ios_base::failure
或派生类的实例,但不太清楚您是否有权抛出其他异常并仍然期望相同的异常行为。事实上,我能发现 underflow()
退出时出现错误的唯一提及是在非规范脚注中,内容如下:
或underflow
可能会因过早抛出异常而失败。其目的不仅是调用不会返回uflow
,而且它们会“立即”返回。eof()
这在两个方向上都没有提供太多指示。它没有具体将例外限制为
failure
,但也没有具体说明它可以是其他东西。而且这是一个非规范性的脚注,所以即使它确实这么说也只能揭示作者的意图,而不是对实现的实际要求。
文本的其余部分主要讨论在执行输入或输出函数期间抛出异常会发生什么(在这种情况下,在开始操作之前会创建一个
sentry
对象,并且对于重新抛出异常有明确的要求)如果设置了 badbit
则例外)。
但是您的代码在尝试从流中读取输入之前就会抛出异常。在这种情况下,不清楚是否应该重新抛出异常。
对我来说,很明显 VC++ 和 g++ 都有某种意图,即您通常应该期望从 VC++ 获得的行为。但我没有看到任何要求您在这些情况下实际上会得到这种行为。所以我想说它们都是正确的,但纯粹作为实现质量问题,VC++ 的行为可能更可取。