2009-10-12 80 views
0

我有一個關於const正確性的隨機問題。Const正確性問題C++

可以說我有一個單身人士的班級。

class Foo : public Singleton<Foo> 
{ 
    friend class Singleton<Foo>; 

public: 
    std::wstring GetOrSet(const int id) const; 

private: 
    Foo(); 
    ~Foo(); 
    void LoadStringIntoMap(const int id, const std::wstring &msg); 

    std::map<int, std::wstring> strMap; 
}; 

的功能被定義爲這樣

std::wstring Foo::GetOrSet(const int stringId) const 
{ 
    if (strMap.find(stringId) == strMap.end()) 
    { 
     Foo::GetInstance()->LoadStringIntoMap(stringId, std::wstring(L"HELLO WORLD222")); 
    } 
    std::map<int, std::wstring>::const_iterator retStr = strMap.find(stringId); 
    return retStr->second; 
} 

void Foo::LoadStringIntoMap(const int stringId, const std::wstring &msg) 
{  
    strMap.insert(std::pair<int, std::wstring>(stringId, msg)); 
} 

如果我直接拿到致電LoadStringIntoMap我得到一個錯誤,它無法this指針從常量富轉換爲foo &。這是有道理的,因爲你在const函數內調用非const函數。但是,爲什麼在調用單例時,這並不是一個問題,並通過它進行修改。

這是不是真的不安全?

這是單身的定義是:

template <typename T> class Singleton 
{ 
protected: 
    Singleton() {}; 
    ~Singleton() {}; 

public: 
    static T *GetInstance() 
    { 
     return (static_cast<T*> (m_This)); 
    } 

    static void Destroy() 
    { 
     if(m_This != NULL) 
      delete m_This; 
    } 

    static void CreateInstance() 
    { 
     m_This = GetInstance(); 

     if (m_This == NULL) 
     { 
      m_This = new T; 
     } 
    } 

private: 
    // Unique instance 
    static T *m_This; 
}; 

template <typename T> T *Singleton<T>::m_This = NULL; 

回答

3

GetInstance()返回非const指針。 由於函數GetInstance()沒有綁定到對象本身,而是整個類,所以可以從const函數調用它。

本質上,你已經欺騙了const環境;但是,你可以從程序的任何上下文/狀態中做到這一點(成員的私密性並不侷限於特定的對象,只有類)。在這種情況下,您必須自己關心安全使用單例訪問器。

+0

由於這是有道理的,我把代碼爲單身。我沒有寫這個代碼,我試圖理解它。 – UberJumper 2009-10-12 16:45:57

0

是的,它只是不安全。

這些工具沒有任何(直截了當)的方式知道Foo :: GetOrSet上的'const'將與Foo :: GetInstance()應用於Foo的相同實例。

'Singleton'不是一個對編譯器意味着什麼的策略。

0

因爲編譯器只關心訪問this。它不會檢查所有可以改變對象的路徑。所以是的,它的工作原理。它不安全嗎?這取決於:)不應該在大多數情況下,但肯定有一系列的情況,可以使其全部倒下。

1

它並不是它的不安全,它完全不合邏輯。如果你不想有一個常量指針,而不是指定函數爲const。它很簡單。無論如何,編譯器無法做很多優化。

它工作的原因是因爲單例傳遞了一個新的指針NOT不是從父函數繼承的。無關緊要,它們都是相同的地址..一個是函數不能使用的const。其中一個不是

1

該代碼說明,如果有一個指向單例的const指針,那麼當您可以隨時通過全局getter獲取對該單例的非常量引用時,它沒有多大意義。全球吸氣者說:「當然,任何人都可以隨時修改物體,這很好。」 const成員函數說:「哦,不,修改這個對象真的很糟糕」。

如果班級不是單身人士,因此不能確定this是指與GetInstance返回的同一個對象,那麼在很多情況下這可能會很有意義。既然他們確實提到同一個對象,並且每個人都知道他們是因爲它是單身人士,他們不可能都是對的。

你永遠不能假定一些全局可訪問的對象不會被修改(至少,你不能假設const的系統將幫助你避免修改它 - 有可能是一些類的其他特性,這保證修改)。因此,無論GetInstance是不安全的,或調用在const Foo成員函數的人的動機是不安全的,這取決於誰是是否對象應在代碼的給定的位被修改實際上是正確的。在這種情況下,我不知道該點是一個定義對象,它是全球範圍內修改的任何const成員函數的東西 - 如果有人有一個常量引用它,那麼他們在何處得到該引用,又爲什麼?是什麼讓任何人想調用的函數「獲取OrSet」應擺在首位常量?

一個選項是GetInstance返回const Foo&,但有一些mutable成員變量,任何人都可以隨時修改,甚至通過const引用。但是這取決於富實際上是什麼:mutable真的應該只用於諸如不修改對象的「可觀察的」保證行爲緩存。