2011-09-07 8 views
1

문자열에서 값을 설정하기 위해 boost :: lexical_cast를 사용할 수있는 원시 타입 래퍼를 만듭니다. 그것은 잘 작동하지만, 어떤 이유로 std :: istream 추출 연산자 failbit를 설정합니다. 다음 프로그램을 인쇄 :std :: istream 추출은 명백한 이유없이 failbit를 설정합니다.

123.45
예외 : ios_base :: failbit는

을 설정하지만 라인 "inStream.exceptions (..."를 주석 경우 작업 및 인쇄 :

123.45
123.45

그것은 당신이 유니 코드로 컴파일하거나하지 않을 경우 차이가되지 않습니다, 또는 INT를 사용하거나 치형으로 떠 경우 failbit는 어떤 경우에 설정됩니다.

#include <conio.h> 
#include <exception> 
#include <iostream> 
#include <string> 
#include <tchar.h> 

#include <boost/lexical_cast.hpp> 

#if defined(UNICODE) || defined(_UNICODE) 
    typedef std::wstring StringType; 
    typedef std::wistream IStreamType; 
#else 
    typedef std::string  StringType; 
    typedef std::istream IStreamType; 
#endif 


#if 1 // Use float 
    typedef float   ValueType; 
    #define VALUE_STRING _T("123.45") 
#else // Use int 
    typedef int    ValueType; 
    #define VALUE_STRING _T("123") 
#endif 


struct Castable { 
    ValueType m_val; 
}; 

inline IStreamType& operator>> (IStreamType& inStream, Castable& castable) 
{ 
    inStream.exceptions(IStreamType::failbit | IStreamType::badbit); 
    inStream >> castable.m_val; 
    return inStream; 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    try{ 
     StringType sVal = VALUE_STRING; 

     ValueType val; 
     val = boost::lexical_cast<ValueType>(sVal); 
     std::cout << val << std::endl; 

     Castable cst; 
     cst = boost::lexical_cast<Castable>(sVal); 
     std::cout << cst.m_val << std::endl; 

    }catch(std::exception& ex){ 
     std::cout << "EXCEPTION: " << ex.what() << std::endl; 
    } 

    _getch(); 
    return 0; 
} 

왜 std :: istream이 문제가 있다고 생각합니까?

답변

2

이 이유 중 하나는 lexical_cast의 구현이 의도적으로 일부 스트림이 실패하여 모든 입력 텍스트가 소비되었는지 확인하려고 할 수 있기 때문일 수 있습니다. 예를 들어, 순진 구현은 다음과 같습니다 여기

template <typename Target> 
    Target lexical_cast(const string& s) { 
    /* Insert the string into a stringstream to use extraction. */ 
    std::stringstream converter(s); 

    /* Pull out an object of type Target, failing if we can't. */ 
    Target result; 
    if (!(converter >> result)) throw bad_lexical_cast(); 

    /* To confirm that we read everything out of the stream, try pulling out a 
    * single character. If we can do this, then there is something left in the 
    * stream that wasn't picked up earlier and the input was malformed. 
    */ 
    char ch; 
    if (converter >> ch) throw bad_lexical_cast(); 

    return result; 
} 

아이디어는 최종 점검 뭔가가 남은 경우 확인하기 위해 스트림을 중단하려고한다는 것입니다. 예외를 활성화하면 failbit으로 감지 할 수있는 정상적인 스트림 오류가 코드에서 예상하지 못한 예외로 바뀝니다.

더 일반적으로 추출 루틴 내에서 스트림 설정을 지정하면 안됩니다. 그것은 발신자가 할 일에 달려 있습니다. 그렇지 않으면 추출 루틴을 호출하기 전에 스트림으로 어떤 작업을 시도해도 루틴이 기본 설정보다 우선합니다. 예외적으로 명시 적으로 예외를 설정 한 다음 예외가 발생했다면 내부적으로 다시 설정했기 때문에 결국 좋지 않습니다. operator >>.

희망이 도움이됩니다.

+0

맞아. 맞아. 따라서 기본적으로 오류를 잡는 것은 lexical_cast의 책임이므로 대상 클래스가 비즈니스가 아닌 일부 실패에 대해 걱정하지 않도록해야합니다. 그리고 lexical_cast는 아무 것도 던지지 않기 때문에 모든 것이 잘됩니다. 난 그냥 "inStream.exceptions (..."줄을 제거해야합니다. – zeroes00