2014-05-10 50 views
1

我無法理解爲什麼這不像我期望的那樣工作。這可能是我使用Visual Studio 2013,但嘿。插入自定義類以映射爲值時出錯

此代碼是我正在寫的遊戲引擎中的項目隨機化系統的一部分。

// the chance a rarity will have a given number of affixes 
std::unordered_map<ItemRarities, ChanceSelector<int>> affixCountChances = { 

std::pair<ItemRarities, ChanceSelector<int>>(ItemRarities::Cracked, 
{ ChanceSelector<int>(
    { ChancePair(int, 100, 0) }) }), 

std::pair<ItemRarities, ChanceSelector<int>>(ItemRarities::Normal, 
{ ChanceSelector<int>(
    { ChancePair(int, 80, 0), 
    ChancePair(int, 20, 1) }) }), 

    // snip for conciseness (there are 3 more) 
}; 

這是ChanceSelector類:

using Percentage = int; 

#define ChancePair(T, p, v) std::pair<Percentage, T>(p, v) 

template <class T> 
class ChanceSelector 
{ 
private: 
    std::unordered_map<T, Percentage> _stuff; 

public: 
    ChanceSelector() 
    { 
    } 

    ~ChanceSelector() 
    { 
     if (_stuff.size() > 0) 
      _stuff.clear(); 
    } 

    ChanceSelector(std::initializer_list<std::pair<Percentage, T>> list) 
    { 
     // snip for conciseness 
    } 

    T Choose() 
    { 
     // snip for conciseness 
    } 
}; 

上面的代碼編譯好,但我有兩個問題:

  1. 爲什麼在STD使用ChanceSelector我不明白::對需要一個默認的構造函數。顯式地,它看起來像我用初始化列表調用構造函數。
  2. 當應用程序運行時,它崩潰,:Unhandled exception at 0x01762fec in (my executable): 0xC0000005: Access violation reading location 0xfeeefeee.

2號消失,如果我只有在地圖一個項目,或者如果我改變affixCountChances到std::unordered_map<ItemRarities, ChanceSelector<int>*>定義(並相應地調整休息)。錯誤轉儲我可以將這些代碼list

for (_Nodeptr _Pnext; _Pnode != this->_Myhead; _Pnode = _Pnext) 
{ 
    _Pnext = this->_Nextnode(_Pnode); // <-- this line 
    this->_Freenode(_Pnode); 
} 

進一步檢查發現在析構函數發生的錯誤。 _stuff爲空:

~ChanceSelector() 
{ 
    if (_stuff.size() > 0) 
    _stuff.clear(); 
} 

它合法地調用析構函數。項目正在從_stuff中刪除,但我不明白爲什麼它會調用析構函數。在所有項目構建完成並且affixCountChances包含所有項目後發生崩潰。我認爲這意味着它會銷燬它創建的所有臨時對象,但我不明白爲什麼它會創建臨時對象。

編輯:

構造ChanceSelector的:

ChanceSelector(std::initializer_list<std::pair<Percentage, T>> list) 
{ 
    int total = 0; 
    int last = 100; 
    for (auto& item : list) 
    { 
     last = item.first; 
     total += item.first; 
     _stuff[item.second] = total; 
    } 
    // total must equal 100 so that Choose always picks something 
    assert(total == 100); 
} 
+0

我還沒有讀完它,但聽起來非常像你有一個錯誤的移動或複製構造函數。還要注意保留的標識符,如_stuff。 – nwp

+0

我已經剪掉了不相關的代碼,使它更小。 –

回答

1

要回答你的兩個問題:

  1. std::pair需要一個默認的構造函數,因爲你可以做這樣的事情

    std::pair<int, MyClass> myPair(); 
    

    它可以創建默認構造函數(一對的值是實際值,而不是引用)類的副本:

    // MSVC implementation 
    template<class _Ty1,class _Ty2> 
    struct pair 
    { // store a pair of values 
    typedef pair<_Ty1, _Ty2> _Myt; 
    typedef _Ty1 first_type; 
    typedef _Ty2 second_type; 
    
    pair() 
    : first(), second() // Here your class gets default constructed 
    {  // default construct 
    } 
    
    // ..... 
    _Ty1 first; // the first stored value 
    _Ty2 second; // the second stored value 
    }; 
    

    一對模板得到全面實施,所以你需要一個默認的構造函數事件,如果你不使用上面的行。爲了避免這種依賴

    一種方法是在std::pair使用指針,這則設置對的第二值,以nullptr默認值:

    std::pair<int, MyClass*> myPair(); 
    
  2. 0xFEEEFEEE是指存儲,你的指針本身存儲的內容已被刪除(例如,在刪除的類引用上工作)。 此刪除似乎發生在您在此處發佈的代碼之外的某處。 更多Magic NumbersMagic Numbers on Wikipedia

編輯:

此外,不要在構造函數調用後存在的初始化列表中的內容。你可能會在那裏複製一個引用,而不是實際的對象,然後被刪除。 std::unordered_map的msvc實現使用std::list作爲存儲項目的基礎。我無法使用給定的代碼提供關於此的更多信息。

Initializer list and lifetime of its content

編輯2:我是能夠重現錯誤與給定的代碼,它不是initializer_list構造函數的內容。 問題似乎是初始化程序列表中對象的生命週期。

當我移動對的聲明無序映射出initializer_list的無序地圖,一切工作正常:

std::pair<ItemRarities, ChanceSelector<int>> pair1(ItemRarities::Cracked, 
    { ChanceSelector<int>(
    { ChancePair(int, 100, 0) }) }); 
std::pair<ItemRarities, ChanceSelector<int>> pair2(ItemRarities::Normal, 
    { ChanceSelector<int>(
    { ChancePair(int, 80, 0), 
    ChancePair(int, 20, 1) }) }); 
std::unordered_map<ItemRarities, ChanceSelector<int>> chances = { 
     pair1, 
     pair2 
    }; 

我不完全知道爲什麼這是一個問題,但我認爲是來自初始化程序列表中的{},那些對象可能會在第一個{}並且在進入實際的intializer_list之前被刪除,這時unordered_map

+0

好的號碼1.在2,嗯。我遺漏的任何代碼看起來都沒有任何關係。沒有任何代碼可以刪除任何內容。我試圖創建一個移動構造函數和賦值操作符(並稱它們!)但這沒有幫助。 –

+0

添加了關於初始化程序列表的一些注意事項 – MarvinPohl

+0

謝謝您的徹底。我已經添加了模板類的構造函數。 –