2013-01-17 36 views
3

我在清理舊的C/C++應用程序的調試宏時遇到了這個問題:我們有一個Tracer類繼承自ostrstream(我知道它自C++ 98以來已被棄用,但是這應用程序寫於1998年),我們使用這樣的:ostrstream將常量字符串解釋爲指針

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

現在,如果在鏈中的第一個值是一個常量字符串像上面,在示蹤調用ostrstream::str()(這是在析構函數完成的結果,將結果插入到隊列中)包含指向此字符串的指針的十六進制表示而不是文本。因此,上述聲明將產生類似"0x401a37 message here"的內容。這與舊的宏沒有發生,因爲它們總是有一個很長的(線程標識符)作爲現在已被刪除的第一個值。

用gdb進入它表明,對於第一次插入,這會在ostrstream上調用operator<<(void const*),而隨後的插入調用operator<< <...>(basic_ostream<...>&, char const*)(爲了便於閱讀,刪除了模板)。

有人可以解釋這種行爲嗎?什麼將是一個乾淨的方法來解決這個問題?我找到了一個簡單的解決方法,它使用<< left作爲第一個參數 - 這是否安全?有沒有更好的方法來做到這一點?

這裏的一個最小化的示例:

所有注意到 operator<<這需要 const char*作爲參數是一個非成員函數的
#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

是這樣工作的,因爲​​是一個臨時的(右值)不能綁定到非const引用operator<<(basic_ostream<...>&,

但是,您可以調用成員函數,如operator<<(void const*),因爲它不需要左值。

成員函數然後返回對流對象的引用,其中可以用調用序列中的下一個operator<<

以這種方式調用任何成員函數,如Tracer() << leftTracer() << flush,因此將該引用「轉換」爲左值引用是相當安全的。

如果您碰巧有一個符合C++ 11的編譯器,那麼標準庫甚至包含一個operator<<(basic_ostream<...>&&,,它可以爲您做到這一點。在這種情況下,您不再需要解決方法。

+0

感謝您的解釋 - 請參閱我對nawaz的回答的評論,對此的最佳解決方法是什麼? – l4mpi

+0

不,標準的做法是像'Tracer()<< flush'來獲取流的左值引用。如果你有最新的編譯器之一,支持右值,它應該無論如何工作。這是C++ 11修訂版中修復的問題。 –

+0

好的,謝謝。有問題的編譯器是g ++ 4.1.2 RedHat,它可悲地不符合C++ 11標準... – l4mpi

5

首先。並且存在一個以void const*作爲參數的成員函數。

在代碼中,表達Trace() << "xyz"可以是僅調用成員函數,因爲Trace()創建temporay,不能結合到所述非成員operator<<函數的第一參數,因爲這些功能採取的第一個參數作爲std::ostream&這是非const引用。所以Trace() << "xyz"解決爲成員operator<<這需要void*作爲參數,它打印的地址!


我的建議:

  • 不要從流類繼承(std::ostrstream棄用反正)。
  • 而是寫在流類和超載operator<<

這裏一個簡單的包裝是一個例子:

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

現在你可以使用它作爲:

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

輸出:

Hello World 
100 
Bye 

Live Demo

+0

感謝您的解釋......但是,我該如何解決這個問題?有沒有比前綴「<< left」給所有調試語句更好的方法? – l4mpi

+0

@ l4mpi:看我的編輯。 :-) – Nawaz

+0

謝謝,這將是實施它的最佳方式...不確定我們是否會使用這個,因爲實際的課程更大更復雜,我們的政策是儘可能少地做出更改到代碼 - 這個應用程序已經快15年了(ostrstream還沒有被棄用,當時^^),而且大多數開發人員已經離開了公司很久以前,所以如果我們破壞了某些東西, – l4mpi