2011-04-12 27 views
6

我一直在研究創建我自己的ostream,以及一個streambuf來處理我的ostream的緩衝區。我其實大部分工作正常,我可以插入(< <)到我的信息流中,並且沒有任何問題。我通過實現虛函數xsputn來做到這一點。但是,如果我輸入(< <)一個float或一個int的流而不是一個字符串xsputn永遠不會被調用。繼承與xsputn和溢出ostream和streambuf問題

我已經通過代碼,我看到該流正在調用do_put,然後f_put,它最終試圖將浮點1字符一次放入緩衝區。我可以讓它調用我的虛函數溢出(int c)的實現,如果我沒有空間離開我的緩衝區,從而得到float和int的數據。

現在,這裏是問題,我需要知道什麼時候float被放入緩衝區。或者換一種說法,我需要知道什麼時候這是最後一次溢出將被調用來傳輸特定的值.xsputn對我的作用的原因是因爲我得到了整個值和它的長度。所以我可以將它複製到緩衝區,然後調用函數等待緩衝區滿。

我承認濫用ostream設計,因爲我需要緩存輸出,然後一次發送所有輸入值(< <)。

無論如何要清楚我會以另一種方式重申我正在拍攝的內容。有一個很好的機會,我只是以錯誤的方式去做。

我想使用一個繼承的ostream和streambuf,所以我可以輸入值,並允許它爲我處理我的類型轉換,然後我想將這些信息傳遞給另一個對象,我將一個句柄傳遞給streambuf(for?)。該對象具有昂貴的I/O,所以我不想一次發送數據1個字符。

對不起,如果這不清楚。並感謝您的時間。

回答

13

這是不是太清楚你在做什麼,雖然它聽起來大致 正確。可以肯定的是:您所有的ostream都提供了 便利的構造函數來創建並安裝您的streambuf, 析構函數,並且可能還會執行rdbuf至 句柄緩衝區的正確類型。假設這是真的: 在您的streambuf中定義xsputn純粹是一種優化。 您必須定義的關鍵功能是overflowoverflow的最簡單的 實現只需要一個字符,並且 將其輸出到接收器。除此之外的一切都是優化:例如,您可以使用setp來設置緩衝區,例如: ;如果你這樣做 ,那麼overflow只會在緩衝區爲 已滿或請求刷新時才被調用。在這種情況下,您還必須使用 輸出緩衝區(使用pbasepptr來獲取 地址)。 (該streambuf基類初始化 指針創建一個0長度緩衝,所以overflow將 呼籲每個字符),你可能 要覆蓋(很)特殊情況下的其他功能:

imbue:如果出於某種原因,您需要使用語言環境。(請記住, 當前字符編碼是區域設置的一部分。)

setbuf:允許客戶端代碼指定緩衝區。 (恕我直言,它的 通常不值得麻煩,但你可能有特殊的 要求。)

seekoff:支持尋求。我從來沒有在 我的streambuf s中使用過這個,所以我不能給出超出標準中可以讀取的 以外的任何信息。

sync:調用flush時,應該將 緩衝區中的任何字符輸出到接收器。如果你永遠不會呼叫setp(所以沒有 緩衝區),你總是同步,這可能是一個沒有操作。 overflowuflow可以調用這個,或者兩者都可以調用一些 單獨的函數。 (關於syncuflow之間的唯一區別是,如果有 緩衝uflow纔會被調用,如果緩衝區是空的它永遠不會被調用。如果客戶端代碼刷新流 sync將被調用。)

當寫我自己的流,除非性能決定 否則,我會保持簡單,並且只覆蓋overflow。 如果性能決定了一個緩衝,我通常把代碼 刷新緩衝區到一個單獨的write(address, length) 功能,並實現沿線overflowsync的 :

int MyStreambuf::overflow(int ch) 
{ 
    if (pbase() == NULL) { 
     // save one char for next overflow: 
     setp(buffer, buffer + bufferSize - 1); 
     if (ch != EOF) { 
      ch = sputc(ch); 
     } else { 
      ch = 0; 
     } 
    } else { 
     char* end = pptr(); 
     if (ch != EOF) { 
      *end ++ = ch; 
     } 
     if (write(pbase(), end - pbase()) == failed) { 
      ch = EOF; 
     } else if (ch == EOF) { 
      ch = 0; 
     } 
     setp(buffer, buffer + bufferSize - 1); 
    } 
    return ch; 
} 

int sync() 
{ 
    return (pptr() == pbase() 
      || write(pbase(), pptr() - pbase()) != failed) 
     ? 0 
     : -1; 
} 

一般來說,我不會與xsputn打擾,但如果您的客戶端 代碼輸出很多長字符串,它可能是有用的。 這樣的事情應該做的伎倆:

streamsize xsputn(char const* p, streamsize n) 
{ 
    streamsize results = 0; 
    if (pptr() == pbase() 
      || write(pbase(), pptr() - pbase()) != failed) { 
     if (write(p, n) != failed) { 
      results = n; 
     } 
    } 
    setp(buffer, buffer + bufferSize - 1); 
    return results; 
} 
+0

這基本上就是我現在所做的,我想知道的是,如果有無論如何要告訴溢出了多少次會被調用,或者當最後char已經過去了。例如,如果我做mystream << 1.3f;我會得到字符'1',然後''。然後'3'但在streabuf裏我無法知道有多少角色可以期待。當我得到3後,我想對緩衝區執行操作(呼叫另一個對象,讓它知道它已準備就緒) – 2011-04-13 15:16:53

+2

代碼無法預先知道客戶端代碼要做什麼,或者它有多少次將被稱爲。你可以在'ostream'上設置'unitbuf':這會在每個'operator <<'(在'sentry'對象的析構函數)末尾調用sync。然後,您在'sync'中對緩衝區執行操作。 – 2011-04-13 17:20:07

+0

aha!這完全是我需要的!把這個標記爲答案,但還是不能投票,一旦我得到足夠的代表,我會回來。非常感謝。 – 2011-04-13 18:34:29