2014-01-12 32 views
0

我試圖讓一個int到int地圖,程序崩潰,我不明白爲什麼。 我總結了這個簡短的代碼的問題。C++:性病::地圖<int,int>崩潰時被分配

當程序啓動時,由於Utilities成員_instance是靜態的,它通過轉到它的構造函數初始化它,它包含一行:int int(簡單)映射賦值。但它然後崩潰。

注意,如果我評論該行,該程序不會崩潰, 並且主要包含了非常同一行。 所以我的兩個問題是:

1)爲什麼它會崩潰?這種行爲背後有一點意義嗎?

2)如何解決它,所以我可以初始化在構造函數中的地圖嗎?

謝謝

#include <map> 

class Utilities 
{ 
public: 

    ~Utilities(){}; 
    static Utilities& instance(); 

private: 
    Utilities(); 
    Utilities(const Utilities&){}; 

    static Utilities _instance; 
    static std::map<int, int> textIntToIntMap; 
}; 


Utilities Utilities::_instance = Utilities(); 
std::map<int, int> Utilities::textIntToIntMap; 

Utilities::Utilities() 
{ 
    //The following line crashes, why? 
    textIntToIntMap[1] = 2; 
} 

int main() 
{ 
    static std::map<int, int> text2; 
    text2[4] = 2; 
    int xxx = 3; 
} 
+0

有真的在*定義*對於一個單獨的類拷貝構造函數是沒有意義的。如果有的話,你只想聲明它,但不定義它,明確地禁止複製。 –

回答

1

你有一個初始化順序問題:

Utilities Utilities::_instance = Utilities(); 

此行調用的Utilities默認構造函數,然後試圖填充地圖。但是地圖在這個階段沒有初始化。

您應該設計你的代碼是反對這樣的初始化順序問題穩健。您可以通過在函數內部創建靜態實例來緩解這一點。這給你一個初始化順序的句柄。但是,定義一個簡單的重新排序應該可以解決眼前的問題:

std::map<int, int> Utilities::textIntToIntMap; 
Utilities Utilities::_instance = Utilities(); // OK, map has been defined 
1

的問題是,你調用Utilities構造Utilities::textIntToIntMap已建成之前。

交換以下兩行的順序:

Utilities Utilities::_instance = Utilities(); 
std::map<int, int> Utilities::textIntToIntMap; 
0

初始化之前_instance您需要定義在類的外部地圖textIntToIntMap。因爲在構造函數中你使用的textIntToIntMap是一個靜態成員,所以你需要先定義它。因此,類使用以下行外:

std::map<int, int> Utilities::textIntToIntMap; 
Utilities Utilities::_instance = Utilities(); 
0

其他人已經抓到了Utilities()Utilities::textToIntMap之前建造的。所以,現在的問題是:未來如何避免這些問題?

您可以使用函數返回一個靜態局部變量的引用,以確保所使用的基準施工前完成。你可以把這樣的功能放到一個名字空間中。你也應該有一個方便的typedef,希望有一個簡短的名字,這樣聲明迭代器並不是C++ 98中的指針。在C++ 11上,您應該始終使用auto

請注意,使用全局或靜態非POD數據是而不是 C++ 98中的線程安全。如果您希望從多個線程安全地使用textToMap(),但不保證在第二個線程啓動之前訪問它,textToIntMap需要將初始化包裝在互斥體中。要大致瞭解如何完成此操作,請參閱Qt方便的Q_GLOBAL_STATIC中的inner function

在這種情況下,單例類的使用看起來像一個毫無意義的Java-ism。

Run a test on ideone

// Utilities.h 
namespace Utilities { 
    typedef std::map<int, int> Map; 
    Map & textToIntMap(); 
} 

// Utilities.cpp 
namespace Utilities { 
    namespace { 
    struct InitializedMap : Map { 
     InitializedMap() { 
     insert(value_type(1, 2)); 
     // or 
     (*this)[1] = 2; 
     } 
    }; 
    } 
    Map & textToIntMap() { 
    static InitializedMap map; 
    return map; 
    } 
} 
0

嘗試這種方式::

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

class Utilities 
{ 
public: 
    static Utilities& instance() { 
     static Utilities instance; 
     return instance; 
    } 
    ~Utilities(){}; 
    void PrintMapValues(); 
    void AddKeyValue(int key, int value); 

private: 
    Utilities(); 
    Utilities(const Utilities&){}; 

    std::map<int, int> int_to_int_map_; 
}; 

Utilities::Utilities() 
{ 
    //The following line crashes, why? 
    int_to_int_map_[-99] = 2; 
} 

void Utilities::PrintMapValues() { 
    for(std::map<int, int>::iterator it = int_to_int_map_.begin(); it != int_to_int_map_.end(); ++it){ 
     cout << "Key:" << it->first << " Val:" << it->second << endl; 
    } 
} 

void Utilities::AddKeyValue(int key, int value) { 
    int_to_int_map_[key] = value; 
} 

int main() 
{ 
    Utilities& utils = Utilities::instance(); 

    for (int i=0; i< 10; i++) { 
     utils.AddKeyValue(i, i+20); 
    } 

    utils.PrintMapValues(); 

    return 0; 
} 
+0

在回答問題時,除了代碼片段之外,還可以提供一些解釋。 – Orilux