2013-10-24 136 views
2

我知道在C++函數中用'static'修飾符聲明的變量只被初始化一次,我想要做的就是用適當的內容初始化靜態動態分配的數組。這裏是我的代碼片段:如何在C++中靜態初始化靜態動態分配的數組?

inline char* getNextPass() 
{ 
    static int chars_num = chars_data.charset_len, pass_len = chars_data.pass_len ; 
    static int *cur_pos = new int[pass_len] ; // this is static variable in function, what means it's initialized only once 

    ... 
    for(int aa = 0; aa < pass_len; aa++) // this is executed every time the function is called. How can I make this code execute only once ? 
    cur_pos[aa] = 0 ; 
    ... 
} 

我當然知道,我可以做這樣的事情:

... 
flag = true ; 
... 
inline char* getNextPass() 
{ 
    ... 
    if(flag) 
    for(int aa = 0; aa < pass_len; aa++) 
    cur_pos[aa] = 0 ; 
    flag = false ; 
    ... 
} 

,但它可能不是編碼的最佳方式,更有效,可以以某種方式完成。我可以通過某種方式使用「靜態」moddifier來實現更優化的實現嗎?

+0

您可以將數組放入類中,在構造函數中初始化它,然後使用該類的'static'實例。 – juanchopanza

+0

與您提供的內容並不完全不同,但也要使標記爲靜態(所以您沒有該全局變量)。但爲什麼你不使用課堂? – clcto

+0

我想要一個相當優化的代碼來編譯給定字符和給定長度的密碼generetor。我認爲代碼會很簡單,沒有類的使用 – user1978386

回答

3

溝指針,以及使用vector

static vector<int> cur_pos(pass_len, 0); 

的好處是,它清除了本身(沒有更多的調用delete)茶清!

1

如果你想要預填充0(看起來你是這麼做的),我能想到的最微小的變化就是用符合C++ 11的工具鏈對該數組進行初始化。即

static int *cur_pos = new int[pass_len](); // note the tail-parens. 

爲了說明它的工作原理,突出顯示的部分適用於如果按照我描述的方式完成初始分配的零填充。

C++ 11§8.5,P10

其初始化爲空集括號的一個目的,即,(),應值初始化

通過值初始化的定義:

C++ 11§8.5,P7

要值初始化類型T的對象是指:

  • 如果T是用戶提供的c(可能是cv-qualified)類類型(第9章) onstructor(12.1),那麼調用T的默認構造函數(並且如果T沒有可訪問的默認構造函數,則初始化不合格);

  • 如果T是沒有用戶提供的構造函數的(可能是cv限定的)非聯合類類型,那麼該對象是零初始化的,並且如果T隱式聲明的默認構造函數不平凡,則該構造函數叫做。

  • 如果T是一個數組類型,那麼每個元素都是值初始化的;然後是

  • 否則,對象是零初始化。

這給我們帶來了什麼可以爲您的對象類型爲零初始化

C++ 11§8。5,P5

要零初始化對象或類型T的參考是指:

  • 如果T是一個標量類型(3.9),該對象被設置爲值0(零) ,取爲整數表達式中,被轉換到T (103)

  • 如果T是一個(可能CV修飾)非工會類型,每個非靜態數據成員,並且每個基礎類子對象是零初始化**,並且填充初始化爲零位;如果T是(可能是cv限定的)聯合類型,則該對象的第一個非靜態命名數據成員是零初始化的,並且將填充初始化爲零位;如果T是聯合類型(可能是cv限定)

  • 如果T是一個數組類型,每個元素都是零初始化的;

  • 如果T是引用類型,則不執行初始化。

103)如4.10所述,將值爲0的整數常量表達式轉換爲指針類型會產生空指針值。

+0

嗯,我用最初添加到MinGW的Dev-C++ 5.4.1,所以我不知道我是否可以使用符合C++ 11的代碼。 – user1978386

+0

@ user1978386你很快就會知道。去嘗試一下。我可以肯定地說它是否有效,但我不知道MinGW能夠完成這個任務。 – WhozCraig

+0

@ user1978386你不需要C++ 11就可以工作。它在C++ 03中工作。 – juanchopanza

0

創建一個名爲AllocAndInit靜態函數,並調用它像這樣(在函數內部分配和初始化你分配的數組):

static int *cur_pos = AllocAndInit(pass_len); 

的AllocAndInit方法應該是這樣的:

int * AllocAndInit(pass_len) 
{ 
    int * ret = new int[pass_len]; 
    for (int i = 0 ; i < pass_len; ++i) 
    // init here .... 

    return ret; 
} 
0

在許多情況下,帶構造函數的全局變量(和函數局部靜態)可能會導致很多意想不到的問題。隨着程序規模和複雜程度的增加,這些事情可能變得很難管理。

如果你明確地管理它們,你會更好 - 因爲那樣你就可以明確地控制構建/破壞的順序以及這些事情何時發生。

如果您使用上面建議的矢量,那麼隨着程序退出,矢量將被釋放。但是,您無法直接控制發生這種情況的順序,所以如果將getNextPass()作爲正在清理的其他部分調用(因此,在main()返回後),它可能會崩潰,您將不得不拼圖瞭解爲什麼以及如何獲得正確的排序。

另請注意,函數局部靜態初始化通常不是線程安全的。 GCC有一個線程安全的初始化機制,但是其他編譯器(如VC)不這樣。即使支持,它也不是免費的,可能需要啓用選項。

否則它手動(非常相似的自動生成的代碼被編譯器):

inline char* getNextPass() 
{ 
    static bool initialized; 
    static int chars_num; 
    static int pass_len; 
    static int *cur_pos; 
    if (!initialized) { 
     chars_num = chars_data.charset_len; 
     pass_len = chars_data.pass_len ; 
     cur_pos = new int[pass_len];  

     for(int aa = 0; aa < pass_len; aa++) 
      cur_pos[aa] = 0 ; 
     initialized = true; 
    } 
    ... 

} 

爲了澄清有點「與構造」是指需要代碼以執行做初始化。 所以,「static int x = 5;」不,但「static int y = rand();」確實。