标准(N3337)说(27.5.3.1.1类ios_base ::失败):
The class failure defines the base class for the types of all objects
thrown as exceptions, by functions in the iostreams library, to report
errors detected during stream buffer operations.
我有一个简单的测试程序,它使用std :: ostringstream模拟受限制的资源环境:
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <sstream>
int main(int argc, const char* argv[])
{
rlimit limit;
limit.rlim_cur = limit.rlim_max = 268435456;
if(setrlimit(RLIMIT_AS, &limit)) {
std::cerr << "Cannot set resource limit: " << strerror(errno) << std::endl;
exit(EXIT_FAILURE);
}
std::ostringstream os;
os.exceptions(std::ostringstream::badbit);
try {
auto iterations = 1024 * 1024 * 1024;
while(iterations && --iterations) os << 'F';
} catch(const std::ios_base::failure& ex) {
std::cerr << "Caught: std::ios_base::failure" << std::endl;
} catch(const std::bad_alloc& ex) {
std::cerr << "Caught: std::bad_alloc" << std::endl;
} catch(...) {
std::cerr << "Caught: ellipsis" << std::endl;
}
return 0;
}
在我的环境(Linux,gcc 5.3.0)中,我得到了陷阱:stder上的std :: bad_alloc. One of online compilers显示相同的输出.
问题是:为什么异常类型是std :: bad_alloc而不是std :: ios_base :: failure?
最佳答案 os<< ‘F’;是运算符<(<(ostream&,char),它是格式化输出函数,并引用27.7.3.6.1 [ostream.formatted.reqmts],
the function endeavors to generate the requested output. If the generation fails, then the formatted output function does
setstate(ios_base::failbit)
, which might throw an exception. If an exception is thrown during output, thenios::badbit
is turned on without causing anios::failure
to be thrown. in*this
’s error state. If(exceptions()&badbit) != 0
then the exception is rethrown
作为输出的一部分,此函数调用stringbuf :: overflow,它在27.8.2.4 [stringbuf.virtuals] p8中指定,以执行重新分配. libstdc和libc之间的区别在于对其分配失败的后果的解释:
在libstdc中,它从stringbuf :: overflow中抛出std :: bad_alloc,它将堆栈一直展开到operator<< (技术上,__ unique_insert),设置badbit并重新抛出,未修改,如上所述. 在libc中,std :: bad_alloc在stringbuf :: overflow中被捕获,它使溢出返回traits :: eof,这反过来使调用者(在本例中为steambuf :: xsputn)返回零,这反过来,使调用者__pad_and_output彻底消灭流的rdbuf,这反过来使其调用者__put_character_sequence设置badbit和failbit.设置那个badbit会引发你抓到的ios ::失败. 也许libc在stringbuf :: overflow中技术上是正确的:标准说
”Returns:”
traits::eof()
to indicate failure.
而且除了分配失败之外,很难想象它失败的方法,但我认为libstdc的解释更接近于意图. (在libstdc中,如果缓冲区容量达到string :: max_size而没有首先命中bad_alloc,则stringbuf :: overflow仍然可以返回eof)