2016-08-23 6 views
4

표준 (N3337)는 (27.5.3.1.1 Class ios_base::failure)를 말한다 :C++ 표준 : : ios_base :: 실패 예외가

클래스 실패가 IOSTREAMS의 기능에 의해, 예외로 던져 모든 객체 의 유형에 대한 기본 클래스를 정의한다 라이브러리에서 스트림 버퍼 조작 중 오류를 감지했습니다. 내가 stderrCaught: std::bad_alloc있어 내 환경 (리눅스, 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; 
} 

:

나는 표준 : : ostringstream의 사용하는 동안 제한된 자원 환경을 에뮬레이트하는 간단한 테스트 프로그램이 있습니다. One of online compilers은 동일한 출력을 보여줍니다.

질문은 다음과 같습니다. 예외 유형이 std::bad_alloc이고 std::ios_base::failure이 아닌 이유는 무엇입니까?

+4

하지만, 메모리 할당에 의해 (버퍼 용량은 제 bad_alloc 타격없이 string::max_size 도달하면 된 libstdc에서 ++, stringbuf::overflow 여전히 eof를 반환 할 수)? –

+0

다시 캡처하여 std :: ios_base :: failure 예외로 채우지 않겠습니까? 나는 메모리 할당 자와 함께 iostream과 함께 일하고있다. – user1641854

+1

그렇게 생각할 수도 있지만, 표준은이를 요구하지 않습니다. 'bad_alloc'이 발생 된 후에 다른 예외를 생성하기위한 공간이 남지 않을 수도 있다는 문제도 있습니다. –

답변

2

os << 'F';는 요청 된 출력을 생성 27.7.3.6.1 [ostream.formatted.reqmts,

함수 노력을 인용 포맷 출력 기능이며, 이는 operator<<(ostream&, char)이다. 생성이 실패하면 형식화 된 출력 함수는 setstate(ios_base::failbit)이되어 예외가 발생할 수 있습니다. 출력 중에 예외가 발생하면 ios::failure이 발생하지 않고 ios::badbit이 켜집니다. *this의 오류 상태. (exceptions()&badbit) != 0 경우 예외 출력의 일부로

을 슬로우 다시되며,이 함수는 재 할당을 수행하기 위해, 27.8.2.4[stringbuf.virtuals]p8에서 지정된 stringbuf::overflow을 호출한다. 된 libstdC++ 여기의 libC++의 차이는 할당 실패의 결과의 해석 :

된 libstdC++에서

그것이 stringbuf::overflow 밖으로 std::bad_alloc을 던져 (기술적 __ostream_insert) operator<<에 스택을 완전히 언 롤링 badbit 설정하고 위에 지정된대로 수정되지 않은 상태로 다시 태어납니다. libc의 ++에서

std::bad_allocstringbuf::overflow 내부 잡힌, 그것은 차례로 호출하게, overflow 복귀 traits::eof (이 경우 steambuf::xsputn) 차례로 호출하게하는 제로 __pad_and_output을 반환하게된다 닦아 스트림의 rdbuf를 완전히 종료 시키면, 호출자 __put_character_sequence이 badbit와 failbit을 모두 설정합니다. 해당 badbit을 설정하면 ios::failure이 나옵니다.

아마의 libC++는 stringbuf::overflow에서 기술적으로 올바른 : 표준은

은 '말한다'반환 '실패를 나타내는 traits::eof()을'.

그리고 할당 실패 이외의 다른 방법으로는 실패하는 것을 상상하기는 어렵지만 libstdC++의 해석은 의도에 더 가깝다고 생각합니다. 예외가 IOSTREAMS 라이브러리가 발생되지 않으므로

0

작성중인 오류 상황은 스트림 버퍼 조작 그 자체로 인한 오류는 아닙니다. 어떤 시점에서 메모리가 부족하면 스트림의 할당자가 bad_alloc을 던집니다. 이것은 당신이보고있는 예외입니다.

bad_alloc을 ios_base :: failure로 다시 게시해야하는지 여부는 논쟁의 여지가 있습니다. 결국, 스트림 작업이 실패하기 때문입니다. 이 경우에도 bad_alloc 상황을보고 놀랍지는 않습니다.

+0

적어도 libC++와 libstdC++ 사이의 동작이 다릅니다. libC++는 std :: bad_alloc을 캡쳐하고 std :: ios_base :: failure를 원래 예외 세부 사항을 잃어 버리게합니다. 따라서 정확히 ENOMEM 조건을 결정하고 DSS 세그먼트의 일부 상수 문자열을 로깅하는 것과 같은 특별한 방법으로 처리 할 수있는 이식성있는 방법은 없습니다. – user1641854