2016-08-23 6 views
4

標準(N3337)は(27.5.3.1.1 Class ios_base::failure)言う:C++のstd :: ios_base ::故障例外

クラス障害は入出力ストリームの関数により、例外としてスローされるすべてのオブジェクト のタイプの基本クラスを定義しますストリームバッファ操作中に エラーが検出されたことを報告します。私はstderrCaught: std::bad_allocを得た私の環境(Linuxでは、GCC 5.3.0)では

#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; 
} 

は私がのstd :: ostringstreamの使用中に制限されたリソース環境をエミュレートし、簡単なテストプログラムを持っています。 One of online compilersは同じ出力を示します。

質問は例外タイプがstd::bad_allocで、std::ios_base::failureではないのはなぜですか?

+4

(バッファ容量は、最初のbad_allocを押すことなくstring::max_sizeに達した場合にlibstdC++では、stringbuf::overflowはまだ、eofを返すことができますか)? –

+0

ios_base :: failure例外のstd :: packに再キャプチャしてパックしませんか?私はメモリアロケータではなくiostreamで作業しています。 – user1641854

+1

あなたはそう思うかもしれませんが、標準はそれを必要としません。また、 'bad_alloc'が発生した後、別の例外を生成するためのスペースが残っていない可能性があるという問題もあります。 –

答えて

2

os << 'F';は、要求された出力を生成する27.7.3.6.1 [ostream.formatted.reqmts]、

機能努力を引用し、フォーマットされた出力関数であり、かつ、operator<<(ostream&, char)あります。世代が失敗した場合、フォーマットされた出力関数はsetstate(ios_base::failbit)となり、例外がスローされる可能性があります。出力中に例外がスローされた場合は、をスローすることなくios::badbitがオンになります。 *thisのエラー状態です。 (exceptions()&badbit) != 0が例外を出力の一部として

を再スローされた場合、この機能は、再配置を実行するために、27.8.2.4[stringbuf.virtuals]p8で、指定されstringbuf::overflowを呼び出します。 libstdC++とのlibC++ここでの違いの割り当て失敗の結果の解釈です:スタックをアンロールのlibstdC++で

、それはstringbuf::overflowの外にstd::bad_allocをスローし、operator<<(技術的には、__ostream_insert)へのすべての方法は、badbitを設定し、上記で指定されているように、改変されず、改変されていない。 libcの++で

std::bad_allocstringbuf::overflowの内側に巻き込まれ、それが今度は、順番に、発信者を作る、呼び出し側(この場合は、steambuf::xsputn)リターン・ゼロを、作る、overflowリターンtraits::eofを行い、__pad_and_output、ワイプされますストリームのrdbufを完全に呼び出し、呼び出し元の__put_character_sequenceをbadbitとfailbitの両方に設定します。そのbadbitを設定すると、あなたが捕まえたios::failureが投げられます。

おそらく、libcの++はstringbuf::overflowで技術的に正しいです:標準は

を言う '' 戻り値: '失敗を示すために' traits::eof()

そして、割り当ての失敗以外では失敗するのは想像もつきませんが、libstdC++の解釈は意図に近いと思います。例外は入出力ストリームライブラリによって、しかしメモリアロケータによってスローされていないので

0

作成しているエラー状況は、ストリームバッファ操作自体に起因するエラーではありません。ある時点では、メモリが足りなくなり、ストリームのアロケータがbad_allocになります。これはあなたが見ている例外です。

bad_allocをios_base :: failureとして再スローするかどうかは議論の余地があります。結局、ストリーム操作が失敗するからです。私はこの場合でもbad_allocの状況を見て驚くことはありません。

+0

少なくともlibC++とlibstdC++では動作が異なります。 libC++はstd :: bad_allocをキャプチャし、std :: ios_base :: failureを元の例外の詳細を失うように再発行します。したがって、正確にENOMEM条件を決定し、それを(DSSセグメントからの一定の文字列を記録するなどの)特別な方法で処理する移植可能な方法はありません。 – user1641854

関連する問題