2009-11-25 83 views
0

我有一些代碼,我不得不寫一些代碼來代替幾千次的函數。這個函數的問題是返回一個指向靜態分配緩衝區的指針,這是一個荒謬的問題。我終於能夠證明間歇性的高負載錯誤是由不好的做法造成的。尋找一些重構建議

我正在更換的功能的簽名爲char * paddandtruncate(char *,int)char * paddandtruncate(float,int)char * paddandtruncat(int,int)。每個函數都返回一個指向靜態分配的緩衝區的指針,該緩衝區在後續調用時被覆蓋

我有三個常量之一

  1. 代碼必須是可更換的與主叫方沒有任何影響。
  2. 很少有時間來解決這個問題。
  3. 可接受的性能。

我想要一些風格和可能的重構想法的意見。

該系統基於用空格填充的固定寬度字段,並且具有一些架構問題。由於該項目的規模大約爲1,000,000行,因此這些地址無法解決。

我最初計劃在創建後允許更改數據,但認爲不可變對象提供了更安全的解決方案。

using namespace std; 
class SYSTEM_DECLSPEC CoreString 
{ 
private: 
    friend ostream & operator<<(ostream &os,CoreString &cs); 

    stringstream m_SS   ; 
    float   m_FltData  ; 
    long   m_lngData  ; 
    long   m_Width  ; 
    string   m_strData  ; 
    string     m_FormatedData; 
    bool   m_Formated ; 
    stringstream SS   ; 


public: 

    CoreString(const string &InStr,long Width): 
      m_Formated(false), 
      m_Width(Width), 
      m_strData(InStr) 
      { 
        long OldFlags = SS.flags(); 
        SS.fill(' '); 
        SS.width(Width); 
        SS.flags(ios::left); 
        SS<<InStr; 
        m_FormatedData = SS.str(); 
      } 

    CoreString(long longData , long Width): 
      m_Formated(false), 
      m_Width(Width), 
      m_lngData(longData) 
      { 
        long OldFlags = SS.flags(); 
        SS.fill('0'); 
        SS.precision(0); 
        SS.width(Width); 
        SS.flags(ios::right); 
        SS<<longData; 
        m_FormatedData = SS.str(); 
      } 

    CoreString(float FltData, long width,long lPerprecision): 
      m_Formated(false), 
      m_Width(width), 
      m_FltData(FltData) 
      { 
        long OldFlags = SS.flags(); 
        SS.fill('0'); 
        SS.precision(lPerprecision); 
        SS.width(width); 
        SS.flags(ios::right); 
        SS<<FltData; 
        m_FormatedData = SS.str(); 
      } 

    CoreString(const string &InStr): 
      m_Formated(false), 
      m_strData(InStr) 
      { 
        long OldFlags = SS.flags(); 
        SS.fill(' '); 
        SS.width(32); 
        SS.flags(ios::left); 
        SS<<InStr; 
        m_FormatedData = SS.str(); 
      } 
public: 
    operator const char *() {return m_FormatedData.c_str();} 
    operator const string&() const {return m_FormatedData;} 
    const string& str() const ; 

}; 

const string& CoreString::str() const 
{ 
    return m_FormatedData; 
} 

ostream & operator<<(ostream &os,CoreString &cs) 
{ 
    os<< cs.m_Formated; 
    return os; 
} 
+1

對不起,有什麼問題嗎?你已經張貼你做了什麼,以及大量的代碼,但沒有實際的問題 – 2009-11-25 17:28:45

+0

我想,如果給任何人能夠想到一個更好的解決方案的限制,我想知道。 – rerun 2009-11-25 18:12:06

回答

2

如果你確實的意思是「對呼叫者沒有影響」,你的選擇是非常有限的。你不能返回任何需要被調用者釋放的東西。

如果冒着將另一個不好的解決方案替換爲另一個解決方案的風險,最快最容易的解決方案可能是這樣的:不是使用單個靜態緩衝區,而是使用它們的池並在每次調用函數時通過它們旋轉。確保選擇緩衝區的代碼是線程安全的。

+0

沒有影響我的意思是儘量不用每次打電話都要評估大量文本。實際上,我們正在通過一組緩衝區進行輪換,並且在過去的幾年中,我們將增加緩衝區的數量,但這是每個新開發人員都需要發現的炸彈。 – rerun 2009-11-25 17:45:42

+0

我想我理解這個問題 - 隨着摩爾定律提供更快的計算機,緩衝區的數量需要增加。肯定的陷阱。 – 2009-11-25 18:03:58

1

你發佈的代碼有一個巨大的問題 - 如果調用者將返回值賦給const char *,編譯器將進行無提示轉換並銷燬臨時的CoreString對象。現在你的指針將會失效。

+0

好抓我懶。我將不得不返回一個字符串作爲副本,但我認爲性能仍然可以接受。 – rerun 2009-11-25 18:24:34

+0

這是一個很好的想法 - 提供自動轉換可最大限度地減少客戶端代碼更改。不過,自動轉換充滿危險。 – 2009-11-25 18:37:20

0

「間歇性高負載錯誤」是由競爭條件引起的,其中一個線程在另一個線程完成使用之前在靜態緩衝區上踐踏,對嗎?

因此,切換到每個線程使用輸出緩衝區,使用您的平臺提供的任何線程本地存儲機制(Windows,我在想)。

沒有同步爭用,線程之間沒有干擾,並根據您對當前實現旋轉緩衝區的說法,幾乎可以肯定調用代碼根本不需要改變。如果當前的實現使用多個緩衝區,它不能依賴每次使用的相同緩衝區。

我可能不會從頭開始設計API,但它實現了您當前的API而不會以顯着方式更改它,或者影響性能。

2

聽起來像系統是線程的,對吧?如果僅僅是在您仍然使用之前的輸出時再次調用其中一個函數是不安全的問題,則它應該每次都以相同的方式運行。

大多數編譯器有辦法來標記變量爲「線程本地數據」使之具有取決於哪個線程訪問它不同的地址。在GCC是__thread,在VC++中的__declspec(thread)

如果您需要能夠從同一個線程多次調用這些功能,而無需重寫的結果,我看不到任何完整的解決方案,但迫使調用者釋放的結果。您可以使用混合方法,其中每個線程都有固定數量的緩衝區,因此無論其他線程在做什麼,呼叫者都可以在不覆蓋以前的結果的情況下組成N個調用。

1

我不知道調用者將如何使用它,但使用new將緩衝區分配到auto_ptr<>可能會起作用。它可能滿足標準1(我沒有看到使用的代碼,我不知道),並可能是一個非常快的修復。最大的問題是它會使用大量的動態內存,這會讓速度變慢。有些事情你可以做,使用新的佈局等,但這可能不是很快就可以編碼。

如果您不能使用動態存儲,你只限於非動態存儲,而且確實沒有什麼可以做,不使用緩衝區或線程局部緩衝或類似的東西的旋轉池。

+0

可能不是。 'auto_ptr的<>'不處理陣列,並且如果變化表明大的代碼是可以接受的,人們可能只切換到使用'的std :: string'和由返回值之一。 – UncleBens 2009-11-25 19:19:56

+0

對,忘了這是一個數組 - 而'std :: string'可能會更好。 – 2009-11-25 20:13:50