2012-10-15 56 views
8

我正在研究爲某些數學類(矩陣,向量等)提供ostream運算符。朋友已經注意到ostream運算符的gcc標準庫實現std::complex包括內部使用一個字符串流將它傳遞給實際ostream之前的輸出格式:在ostream函數中使用stringstream

/// Insertion operator for complex values. 
template<typename _Tp, typename _CharT, class _Traits> 
    basic_ostream<_CharT, _Traits>& 
    operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x) 
{ 
    basic_ostringstream<_CharT, _Traits> __s; 
    __s.flags(__os.flags()); 
    __s.imbue(__os.getloc()); 
    __s.precision(__os.precision()); 
    __s << '(' << __x.real() << ',' << __x.imag() << ')'; 
    return __os << __s.str(); 
} 

這種模式升壓可見也。我們試圖確定這是否值得關注。有人擔心它涉及到爲字符串流包含一個額外的頭文件,並且可能會避免字符串流中需要額外的堆分配。

最合理的建議是,如果客戶端需要該功能,那麼他們可以創建字符串流並自行進行預傳。

任何人都可以幫助我理解爲什麼這將被認爲是良好的做法,我是否應該採用它?

回答

6

考慮,如果你設置的ostream的輸出寬度會發生什麼,然後寫一個std ::複雜 - 你不想寬度隻影響第一輸出操作(即'('字符)

std::complex i(0, 1); 
std::cout << std::setw(10) << std::left << i; 

這應該打印"(0,1)     ""(         0,1)"

通過形成作爲單個字符串整個輸出然後寫出來的輸出榮譽字段寬度和在流上設置其他格式標誌。

2

該模式的一個主要目的是避免保留原始流的操縱器/標誌並在返回之前重置它們。 Boost.IoStateSavers避免了這個需要,所以我會說使用這個庫是一個更好的做法。

4

在另一個響應中引用的線程原因並不會真正解決:字符串仍然可以在流緩衝級別上拆分,因爲這些操作在從多個線程調用時不是原子的。

然而,有兩個考慮因素是相關的:

  1. 對於要臨時更改格式標誌設置一定的輸出。例如,要確保某個字符串以十六進制表示形式出現,用於其他十進制表示法,並且希望將該流恢復到其原始狀態。
  2. 更重要的是,輸出的width()的含義是整個格式字符串至少應占用的字符數。如果在內部將輸出運算符用於另一個輸出運算符,則會使第一個元素佔用寬度,而不是由多個組件組成的整個字符串。例如,對於複數,實數元素將佔用width(),而不是實數元素,逗號和虛數元素的組合。