2016-10-22 57 views
1

考慮以下幾點:避免檢查可能發生,如果

class ReadWrite { 
public: 
    int Read(size_t address); 
    void Write(size_t address, int val); 
private: 
    std::map<size_t, int> db; 
} 

在讀功能訪問其以前沒有寫是爲了我想要麼拋出異常指定這樣的錯誤或允許並返回0地址的時候,在其他字我想要使用std::map<size_t, int>::operator[]()std::map<size_t, int>::at(),取決於用戶可以設置的一些布爾值。所以,我添加以下內容:

class ReadWrite { 
public: 
    int Read(size_t add) { if (allow) return db[add]; return db.at(add);} 
    void Write(size_t add, int val) { db[add] = val; } 
    void Allow() { allow = true; } 
private: 
    bool allow = false; 
    std::map<size_t, int> db; 
} 

的問題,那就是: 通常情況下,該方案將允許有一個呼叫或沒有在節目的開頭,然後再把許多的訪問。因此,性能方面,這個代碼很糟糕,因爲它每次執行檢查if (allow),通常它總是爲真或者總是爲假。 那麼你會如何解決這個問題?

編輯:

雖然這個類的描述使用情況下(在第一次或無Allow())很可能它不是明確的,所以我必須允許用戶調用Allow()動態。

另一個編輯:

的解決方案,使用函數指針:有關使用函數指針是不能夠由編譯器進行在線支付的性能開銷是什麼?如果我們使用std::function而不是解決這個問題?

+3

如果這確實是您的性能瓶頸? –

+0

不,我沒有,但它仍然是不必要的檢查,它是困擾我 –

+1

1)如果你想要的功能沒有必要。 2)你不知道編譯器和cpu會做什麼優化3)即使沒有必要,也沒有編譯器和cpu完成的優化,這個問題仍然是[過早優化](https:// xkcd (這是所有邪惡的根源,順便說一句)(http://stackoverflow.com/questions/385506/when-is-optimisation-premature)) – zvone

回答

0

如果你想減少時間成本,你必須增加內存成本。接受這一點,你可以用一個函數指針來做到這一點。下面是我的回答:

class ReadWrite { 
public: 
    void Write(size_t add, int val) { db[add] = val; } 
    // when allowed, make the function pointer point to read2 
    void Allow() { Read = &ReadWrite::read2;} 
    //function pointer that points to read1 by default 
    int (ReadWrite::*Read)(size_t) = &ReadWrite::read1; 
private: 
    int read1(size_t add){return db.at(add);} 
    int read2(size_t add) {return db[add];} 
    std::map<size_t, int> db; 
}; 

函數指針可以被稱爲其他成員函數。作爲一個例子:

ReadWrite rwObject; 
//some code here 
//... 
rwObject.Read(5); //use of function pointer 
// 

注意,非靜態數據成員初始化可用與C++ 11,所以int (ReadWrite::*Read)(size_t) = &ReadWrite::read1;可以不與舊版本的編譯。在這種情況下,你必須顯式聲明一個構造函數,可以完成函數指針的初始化。

+0

是的,我正在尋找這樣的事情。但你爲什麼要公開所有這些?這些應該不是私有的,只有一個調用函數指針的Read函數? –

+0

是的,你是對的。編輯! –

0

您可以使用指針功能。

class ReadWrite { 
public: 
    void Write(size_t add, int val) { db[add] = val; } 
    int Read(size_t add) { (this->*Rfunc)(add); } 
    void Allow() { Rfunc = &ReadWrite::Read2; } 
private: 
    std::map<size_t, int> db; 
    int Read1(size_t add) { return db.at(add); } 
    int Read2(size_t add) { return db[add]; } 
    int (ReadWrite::*Rfunc)(size_t) = &ReadWrite::Read1; 
} 
1

通常情況下,該方案將允許有一個呼叫或沒有在 開始計劃的,然後再把許多的訪問。所以, 表現明智,這個代碼是壞的,因爲它每次執行 檢查,如果(允許)通常在哪裏總是爲真或總是 錯誤。那麼你將如何解決這個問題?

我不會,CPU會的。
Branch Prediction會發現答案在很長一段時間內最有可能相同,所以它能夠非常好地在硬件級別優化分支。它仍然會產生一些開銷,但是可以忽略不計。

如果您確實需要優化您的程序,我認爲您最好使用std::unordered_map而不是std::map,或者轉到更快的地圖實施,如google::dense_hash_map。與地圖查找相比,該分支不重要。

0

如果你想運行時動態行爲,你必須在運行時支付它(在你希望你的邏輯動態行爲的地方)。

根據運行時間條件,您需要根據不同的行爲調用Read,並且您必須檢查該條件。 無論您的overhad是函數指針調用還是分支,您都可以在程序中的不同位置找到跳轉或調用,具體取決於allow,其中Read由客戶端代碼調用。

注意:配置文件並修復真正的瓶頸 - 不是可疑的瓶頸。 (如果您通過確認您的懷疑或找出您對性能假設的錯誤原因,您將瞭解到更多信息。

+0

我同意存在運行時開銷,我無法完全避免。問題是如果使用std :: function而不是函數指針,這個開銷是否不那麼重要? –

+0

@HannaKhalil:個人資料。在這種情況下,我不認爲'std :: function'可以做的不僅僅是函數指針。正如我指出的那樣,最終你會讀到一個目標地址,然後跳到那個地址。 – Pixelchemist

相關問題