2010-07-31 34 views
5

我試圖映射一些結構的一些其他情況下,像這樣:存儲結構實例::地圖

template <typename T> 
class Component { 
public: 

    typedef std::map<EntityID, T> instances_map; 

    instances_map instances; 

    Component() {}; 

    T add(EntityID id) { 
     T* t = new T(); 
     instances[id] = *t; 
     return *t; 
    }; 
}; 

然後我用這樣的:

struct UnitInfos { 
    int owner_id; 
    int health; 
    float x, y; 
}; 

class LogicComponent : public Component<UnitInfos> {}; 

的問題是,當它在以後檢索以後,這樣的數據:

comp.instance[id]; 

我得到的缺省值初始化性能breand新的對象。

這段代碼是否有內在的錯誤,或者我是否遺漏了關於該問題的信息?


作爲每@aaa建議,我改變代碼

typedef std::map<EntityID, T> instances_map; 
instances_map instances; 
T& add(EntityID id) { 
    instances[id] = T(); 
    return instances[id]; 
}; 

但是當我訪問它

UnitInfos &info = logic_c.instances[id]; 

info.x的值是0還是任何指針?


問題是我如何將LogicComponent的引用存儲在另一個類中。使用LogicComponent logic_c;而不是LogicComponent& logic_c;。它現在可以工作,但我在地圖中存儲指針(而不是@ aaa的建議)。這是一個壞主意嗎?

+1

有_is_一些固有的毛病這段代碼:不要動態創建'T'。沒有理由這樣做,而且現在寫下來,你會泄漏那個對象。至於你所看到的問題,你需要在地圖上發佈「EntityID」的小於運算符的實現以及你如何在地圖上調用operator []'(例如,你如何創建你傳遞給'運算符[]'?)。 – 2010-07-31 02:26:06

+0

EntityID被定義爲'typedef unsigned long EntityID;'。 – sharvey 2010-07-31 02:30:42

回答

3

闡明您想要在LogicComponent上執行的操作。假設你正在努力實現這樣的事情:

第1步:添加新條目圖:

LogicComponent comp; 
EntityID id = 99; 
UnitInfos info = comp.add(id); 

第2步:初始化信息:

info.x = 10.0; 
info.y = 11.0 
// etc 

第3步:獲取再次info對象:

UnitInfos info2 = comp.instances[id]; // this is uninitialized. 

然後,幾個代碼註釋是爲了:

comp.add返回的info對象是您添加到地圖的對象的COPY。通過修改它,你不會修改地圖中的內容。

最簡單的方法是創建一個指向對象的指針映射而不是對象本身。

typedef std::map<EntityID, T*> pinstances_map; 

T * add(EntityID id) { 
    T* t = new T(); 
    instances[id] = t; 
    return t; 
}; 

// initialize as 
UnitInfo *info = comp.add(id); 
info->x = 10.0; 
info->y = 11.0; 

// retrieve as 
UnitInfos *info = comp.instances[id]; 

另外,請使用訪問器方法獲取映射值,而不是將公開地圖對象。使實例變量受保護,並添加一個公共get()方法。

編輯:此代碼工作正常,我:

#include <map> 
#include <iostream> 
using namespace std; 

template<typename T> 
class Component 
{ 
public: 
     typedef map<long, T*> pinstances_map; 
     pinstances_map instances; 

     T * add(long id) 
     { 
       T *t = new T(); 
       instances[id] = t; 
       return t; 
     } 
}; 

struct UnitInfo 
{ 
     float x, y; 
}; 

class LogicComponent: public Component<UnitInfo> {}; 

int main() 
{ 
     LogicComponent comp; 
     UnitInfo *info = comp.add(99); 
     info->x = 10.0; 
     info->y = 11.0; 

     UnitInfo *info2 = comp.instances[99]; 
     cout << info2->x << " " << info2->y; 

     return 0; 
} 
+0

你所描述的正是我想要實現的。切換到你所描述的是我試過的一些想法,但是當你在最後一行後面調用info-> x時,我得到一個EXC_BAD_ACCESS,信息指向0x0。 – sharvey 2010-07-31 03:51:15

+0

我同意,此代碼有效。當我嘗試從代碼的另一部分訪問它時(渲染函數傳遞給'glutDisplayFunc'和'glutIdleFunct',指針仍然指向0x0。 – sharvey 2010-07-31 04:51:49

+0

您是否訪問同一個LogicComp對象? – carlsborg 2010-07-31 05:11:48

4

可能是

T add(EntityID id) { 
    T* t = new T(); 
    instances[id] = *t; 
    return *t; // return value and map instance are not the same anymore 
}; 

應該

T& add(EntityID id) { 
    instances[id] = T(); 
    return instances[id]; 
}; 
+0

我試着改變代碼,但它仍然給我同樣的問題。我應該像這樣檢索實例:'UnitInfos info = logic_c.instances [id];'? – sharvey 2010-07-31 02:40:13

+0

@sharvey否,'UnitInfos info'是一個新的實例,'UnitInfos&info'是對現有實例的引用。如果您來自Java,您可能需要閱讀以下內容:http://www.parashift.com/c++-faq-lite/references.html – Anycorn 2010-07-31 02:41:40

+0

我確實來自java-ish背景。奇怪的是,當我改變它後立即訪問它,值是正確的;但是當我以後再次得到它時,x的值仍然是0.我更新了這個問題。謝謝。 – sharvey 2010-07-31 02:53:58

2

這聽起來像你定義你的索引操作符爲:

template <typename T> 
T& Component::operator[](EntityID id) 
{ 
    return instances[id]; 
} 

或類似的東西。

這樣做的可能意想不到的效果是,它會自動插入的T默認構造的實例到地圖中,然後返回它非exising項。這在std::map完成,所以自然分配語法如instances[10] = t;工作。

這裏的關鍵是constness。把它定義爲上述一致,除了按值,並用const屬性返回:

template <typename T> 
T Component::operator[](EntityID id) const 
{ 
    return instances[id]; 
} 

這樣,當您嘗試通過不存在的關鍵字進行檢索,你會得到一個異常。更重要的是,剛剛typedef像波紋管,並用它做:

typedef std::map<EntityID,UnitInfos> EntityUnitMap; 

其他已經提到過,你並不需要動態分配一個對象 - 你存儲在容器中的副本呢 - 和你的內存泄漏當你這樣做。

+0

謝謝,我現在明白爲什麼C++ faq-lite說你可能不需要大多數時間在C++中的指針。沒想到它也適用於這樣的事情。 我正在通過實例子字段訪問實例,所以我沒有在組件模板上調用[]運算符。當然,我可能是錯的。 我絕對會像你所建議的那樣實現operator [],因爲它更好。謝謝。 – sharvey 2010-07-31 03:03:18