2016-02-27 20 views
4

可以說我有一個不可改變的類C。從用戶的角度來看,我們決不能改變任何對象的功能行爲。const應該用於捕獲錯誤或文檔?

但是,出於性能原因,可以說我們有一個toString方法將對象轉換爲字符串並返回它。我不希望每次都進行這種計算,所以我將結果存儲在一個成員變量中,所以如果用戶再次調用toString,它將會很快。

難道我讓toString功能const(和只使用const_cast存儲結果),因爲只要我們從接口和實現分離,toString應該不會修改物體進行處理,或者我應該讓非const的,因爲它會幫助編譯器捕獲錯誤?

+1

用一些代碼問這個問題會更好。 –

+14

更好的方法是使成員變量'mutable' –

+0

或者,你可以分離一個對象及其緩存,在一組對象之間共享緩存[也許是不同類型的。 – user3159253

回答

2

有一個const對象的目的是爲了保證它不會在某些例程的過程中被改變。這完全是爲了向其他開發人員傳達你的意圖,並向優化器提供信息,因爲const不存在於機器代碼級別。

Const對象只允許調用const方法,否則被聲明爲const的對象可能通過調用它的方法之一來改變其值,方法是首先調用其中的一個方法,使其成爲const。因此,在編寫類時儘可能將方法標記爲const,以便該類的const對象可以調用這些方法。

有幾個實現會給你你想要的。這是一個應該爲你工作的設計,因爲我對你當前的要求知之甚少。這會在構造函數中創建字符串,因爲即使對象被聲明爲const,構造函數也可以修改該對象。然後,每次調用toString()時都會檢索預先填充的字符串,並且不需要mutable關鍵字(第二個示例中的更多內容)。我希望你不要介意我用什麼樣的字符串來構建它的自由,以及應該怎樣實際應用它。

class ImmutableClass 
{ 
private: 
    std::string strTextRepresentation; 

public: 

    int nValue1, nValue2, nValue3; //variables that are to be used in the string 

    ImmutableClass(int nValue1, int nValue2, int nValue3): 
     nValue1(nValue1), nValue2(nValue2), nValue3(nValue3) 
    { 
     std::stringstream ss; 
     ss << nValue1 << ',' << nValue2 << ',' << nValue3; 

     strTextRepresentation = ss.str(); 
    } 

    const std::string& toString() const 
    { 
     return strTextRepresentation; 
    } 
}; 

正如多德在評論中提及上面,你也可以得到你想要用的是什麼可變的關鍵字。優點是你可以'延遲加載'字符串。如果在類實例化時構造字符串的開銷太大(可能因爲您需要很多這些類,並且很少有這些類會調用toString()方法),這是一個不錯的選擇。

class ImmutableClass 
{ 
private: 
    mutable std::string strTextRepresentation; 

public: 

    int nValue1, nValue2, nValue3; //variables that are to be used in the string 

    ImmutableClass(int nValue1, int nValue2, int nValue3): 
     nValue1(nValue1), nValue2(nValue2), nValue3(nValue3) 
    { 
    } 

    const std::string& toString() const 
    { 
     //NOTE: consider using another kind of check for if the string 
     //has been set. I recommend an optional<T> wrapper (easy to implement, or see the boost library) 
     if (strTextRepresentation.size() == 0) 
     { 
      std::stringstream ss; 
      ss << nValue1 << ',' << nValue2 << ',' << nValue3; 

      strTextRepresentation = ss.str(); 
     } 

     return strTextRepresentation; 
    } 
}; 

無論是那些應該工作,誠實有幾個人,但這些人都沒有好各種原因,即使他們在技術上的工作。你對const_cast對象的想法是其他方法之一,因爲你聲明一個對象是常量,然後在同一抽象層次上說它在一種情況下並不是真正的恆定。如果有其他選擇,const_cast應該幾乎不會被使用。

1

Const有多種用法,首先const對文檔很重要。我知道人們對此持不同意見,儘管它清楚地表明瞭成員函數的意圖或函數的參數。

其次,它可以防止錯誤,當您指出意圖,並且您碰巧調用了錯誤的函數(非const)時,這會導致編譯錯誤。所以無論你的意圖是錯誤的還是該函數都不應該被調用。

最後,規則也有例外。無論什麼時候你有一些懶惰的實現,你應該使用mutable,因爲適應一個可變成員是允許的(在所有的翻譯單元中是已知的,因爲在頭文件中),而修改const-cast是未定義的行爲(隱藏在單個函數實現中)。就個人而言,我對使用mutable感到混淆,因爲在多線程中你必須小心。 (所以你需要正確的鎖定,std :: call_once ...或者你需要知道這不是在多線程代碼中調用的)

關於const-cast和mutable的更多細節可以在7.1中的標準中找到.6.1和5.2.11

除了任何類成員聲明可變(7.1.1)可以被修改,任何試圖在其壽命期間修改const對象(3.8)導致未定義的行爲。

通常人們會通過const來優化。雖然這比你想象的要難得多。我一直在關注這個clang編譯器:http://lists.llvm.org/pipermail/llvm-dev/2015-October/091178.html 你可以看到目前只有一個概念驗證實現。 (我不熟悉的其他實現)

所以在最後:

  • 常量同時用於文檔和防止出錯。
  • 使用mutable over const_cast。