2013-01-17 4 views
3

이전 C/C++ 응용 프로그램의 디버그 매크로를 정리하는 동안이 문제가 발생했습니다. ostrstream에서 상속 한 Tracer 클래스가 있습니다. C++ 98 이후로 더 이상 사용되지 않지만 응용 프로그램은 1998 년에 기록 된) 우리는 다음과 같이 사용하는!ostrstream는 상수 문자열을 포인터로 해석합니다.

Tracer() << "some" << " message" << " here"; 

이제 체인의 첫 번째 값은 위와 같이 상수 문자열, 소멸자에서 수행하는 (트레이서에 ostrstream::str()를 호출 한 결과 인 경우 결과를 대기열에 삽입)에는 텍스트 대신이 문자열에 대한 포인터의 16 진수 표현이 포함됩니다. 따라서 위의 진술은 "0x401a37 message here"과 같은 것을 얻을 것입니다. 이전 매크로에서는 항상 제거 된 첫 번째 값으로 long (스레드 ID)을 사용 했으므로 이런 현상은 발생하지 않았습니다.

gdb를 사용하여 첫 번째 삽입시에는 operator<<(void const*)이 ostrstream에 호출되고 후속 삽입은 operator<< <...>(basic_ostream<...>&, char const*) (가독성을 위해 제거 된 템플릿)이 호출됩니다.

누군가가이 동작을 설명 할 수 있습니까? 이 문제를 해결할 수있는 방법은 무엇입니까? 나는 쉬운 해결책을 발견했다. 이것은 첫 번째 인수로 << left을 사용하고있다. 이것은 안전한가요? 이 작업을 수행하는 더 좋은 방법이 있습니까? 인수 const char* 얻어 operator<< 비 멤버 함수임을 모든 노트

#include <strstream> 
#include <iostream> 

using namespace std; 

class Trace : public ostrstream { 
    public: 
     Trace(); 
     virtual ~Trace(); 
}; 

Trace::Trace() : ostrstream() {} 
Trace::~Trace() { 
    static_cast< ostrstream& >(*this) <<ends; 
    char * text = ostrstream::str(); 
    cout << "MESSAGE: "<< text <<endl; 
    delete[] text; 
} 

int main(){ 
    Trace() << "some" << " text" << " here"; 
    Trace() << left << "some" << " text" << " here"; 
    Trace() << 123 << " text" << " here"; 
} 

답변

5

그것은이 방식으로 작동합니다.

그러나 lvalue가 필요하지 않기 때문에 operator<<(void const*)과 같은 멤버 함수를 호출 할 수 있습니다.

다음 멤버 함수는 시퀀스에서 다음 operator<< 호출에 사용할 수있는 스트림 개체에 대한 참조를 반환합니다.

Tracer() << left 또는 Tracer() << flush과 같은 멤버 함수를 호출하여 참조를 왼쪽 값 참조로 "변환"하는 것은 매우 안전합니다.

C++ 11 호환 컴파일러가있는 경우 표준 라이브러리에는 operator<<(basic_ostream<...>&&,도 포함되어 있습니다. 이 경우 더 이상 해결 방법이 필요하지 않습니다.

+0

설명 주셔서 감사합니다 - 내 의견을 nawaz '대답을 참조하십시오 무엇이 최선의 해결 방법이 될 것이라고? – l4mpi

+0

아니요, 표준 방법은 'Tracer() << flush'와 같은 작업을 수행하여 스트림에 대한 좌변 값 참조를 얻는 것입니다. 그리고 만약 rvalue를 지원하는 최신 컴파일러가 있다면 어쨌든 작동 할 것입니다. 이 문제는 C++ 11 개정판에서 수정되었습니다. –

+0

알겠습니다. 고마워요. 문제의 컴파일러는 g ++ 4.1.2 RedHat입니다. 슬프게도 C++ 11을 준수하지 않습니다 ... – l4mpi

5

첫째

여기 최소화 예이다. 그리고 인자로 void const*을 취하는 멤버 함수가 존재합니다. 코드에서

, Trace() << "xyz"는 멤버 함수를 호출 할 수있는 표현, Trace()는 이러한 기능이 std::ostream& 바와 같이, 제 1 인수를 같이 operator<< 기능 비회원의 첫 번째 매개 변수에 바인딩 할 수없는 temporay을 만들기 때문에 비 const 참조. 따라서 Trace() << "xyz"회원 인operator<<으로 변환되며 주소를 인쇄하는 데는 void*이 인수로 사용됩니다.


내 조언 :

  • 가 스트림 클래스에서 상속하지 마세요 (std::ostrstream입니다 어쨌든을 사용되지 않음).

    Trace() << "Hello World\n" << 100 << "\nBye\n"; 
    

    출력 :

    #include <sstream> //for std::ostringstream 
    
    struct Trace 
    { 
        std::ostringstream ss; 
    
        template<typename T> 
        Trace& operator << (T const & data) 
        { 
         ss << data; 
         return *this; 
        } 
        ~Trace() 
        { 
         std::cout << ss.str() << std::endl; 
        } 
    }; 
    

    지금 당신이로 사용할 수 있습니다 :

  • 은 오히려 스트림 클래스와 operator<<

여기에 과부하를 통해 간단한 래퍼를 작성하는 것은 한 예입니다

Hello World 
100 
Bye 
operator<<(basic_ostream<...>&,에 const가 아닌 참조에 바인딩 할 수있는 임시 (를 rvalue)이 있기 때문에 6,

Live Demo

+0

설명 주셔서 감사합니다 ...하지만 어떻게 해결합니까? 모든 디버그 명령문에'<< left'를 추가하는 것보다 더 좋은 방법이 있습니까? – l4mpi

+0

@ l4mpi : 편집을 참조하십시오. :-) – Nawaz

+0

고맙습니다, 이것이 이것을 구현하는 가장 좋은 방법이었을 것입니다 ... 실제 클래스가 다소 크고 복잡해지면서 우리가 이것을 사용한다면 확실하지 않습니다. 우리의 정책은 가능한 한 적은 변경을하는 것입니다. 코드에 -이 응용 프로그램은 거의 15 세입니다. (ostrstream은 아직 사용되지 않았지만 ^^) 대부분의 개발자는 회사를 오래 전에 떠났습니다. 그래서 우리가 뭔가를 망가 뜨린다면, – l4mpi

관련 문제