2010-06-25 60 views
2

我有一個static std::map<std::string, CreateGUIFunc>在基本上持有字符串標識gui類型的類,CreateGUIFunc是對工廠函數的引用。std ::只讀位置的地圖分配

在我的構造函數中我有

if (m_factoryRef.size() == 0) { 
    m_factoryRef["image"] = &CreateGUI<Image>; 
    m_factoryRef["button"] = &CreateGUI<Button>; 
} 
... 

然而,這給了我一個錯誤說assignment of read-only location ‘GUIManager::m_factoryRef.std::map<_Key, _Tp, _Compare, _Alloc>::operator[] [with _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Tp = GUI*(), _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, GUI*()> >](((const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)(& std::basic_string<char, std::char_traits<char>, std::allocator<char> >(((const char*)"image"), ((const std::allocator<char>&)((const std::allocator<char>*)(& std::allocator<char>())))))))’|

我不知道爲什麼這是一個只讀的分配。我也嘗試將其更改爲普通成員,以查看是否它可能是靜態的,但同樣的事情。

什麼問題?

編輯:一些定義,以使事情多一點明確

// these are all private 

typedef GUI* CreateGUIFunc(); 

template<class T> 
GUI* GUIManager::CreateGUI(std::string &filepath, int x, int y) { 
    return new T(filepath, x, y); 
} 

static std::map<std::string, CreateGUIFunc> m_factoryRef; 

附:如果有更清晰的方式來初始化靜態地圖請讓我知道。

+2

你可以修改地圖的定義,並添加CreateGUIFunc和CreateGUI的定義(不是完整的類,只是爲了讓我們看看它是什麼),甚至更好的可能是最小的selfcontained程序的整個代碼重現問題。 – nus 2010-06-26 00:10:59

+1

據我可以告訴你有模板和參考有點混在這裏。 '&'前綴不是引用,但是如果我沒有錯誤,則「操作符的地址」和「CreateGUI 」不是對象的有效名稱。 – nus 2010-06-26 00:26:40

+1

如何聲明'm_factoryRef'? – 2010-06-26 00:27:26

回答

0

在C++中,typedef GUI* CreateGUIFunc();不是具有未指定參數的函數,而是具有NO參數的函數。所以你的功能都不符合這種類型。你想要的是typedef GUI* (*CreateGUIFunc)(std::string &filepath, int x, int y);

接下來,嘗試使用地圖的insert成員函數而不是下標運算符,這樣你就不會偶然調用常量版本。

+0

好的,我比解釋函數指針有什麼問題更接近我,但是在下標操作符上它應該起作用,如果它不起作用,那麼除了事故之外,它不應該起作用... – nus 2010-06-26 00:53:21

1

以下是對當前C++的一些替代初始化。當你說你的代碼在構造函數中時,我不確定你的意思是「靜態」初始化。我有一些猜測,但沒關係。選擇對你來說「更清潔」的東西。

if (m.empty()){ 
    m.insert (map<K,V>::value_type (k1, v1)); 
    m.insert (map<K.V>::value_type (k1, v1)); 
} 

,或者

map<K,V>& getmap() { 
    static map<K,V>* m = 0; 
    if (!m){ 
     m = new map<K,V>(); // never deleted. 
     // insert. 
    } 
    return *m; 
} 

,或者

namespace /*anon*/ { 
     map<K,V>* init_map() { 
     map<K,V>* m = new map<K,V>(); 
     // insertions here. 
     return m; // return by val. can move in c++0x. 
     } 
} 

map<K,V> Foo::m = *init_map(); 

,或者

namespace /*anon*/ { 
      map<K,V>* init_map() { 
      map<K,V>* m = new map<K,V>(); 
      // insertions here. 
      return m; // return by val. can move in c++0x. 
      } 
} 

map<K,V>& Foo::get_map() { /* static singleton accessor */ 
    static map<K,V> * m = init_map(); 
    return *m; 
} 

的圖案應該是顯而易見的。你必須解決兩個問題:僅僅一次初始化該死的東西這個微不足道的問題,以及防止靜態初始化命令失敗的棘手問題。我的人的偏好就像上面的第二種情況。

+0

+1提供各種解決方案。我建議保持清除#1,並認爲#2簡單明瞭。值得注意的是,所有這些情況在多線程上下文中都很容易出現問題(如果Foo是第一次由兩個線程同時構建的話)。 – stinky472 2010-06-26 02:00:24