簡體   English   中英

局部范圍靜態變量的零初始化和靜態初始化

[英]zero initialization and static initialization of local scope static variable

我從Google閱讀了有關C ++初始化的幾篇文章,其中一些將我引到StackOverflow上。 我從這些帖子中挑選的概念如下:

  • C ++的初始化順序為:
    1. 零初始化 ;
    2. 靜態初始化 ;
    3. 動態初始化
  • 靜態對象 (包括變量)首先被零初始化 ,然后被靜態初始化

我有一些關於初始化問題的查詢( 存儲類問題也可能與此有關):

  • 全局對象 (未使用static關鍵字定義)也是靜態對象,對嗎?
  • 全局對象也像靜態對象一樣通過上述兩個步驟初始化,對嗎?
  • 什么是靜態初始化 它是否涉及初始化靜態對象(使用static關鍵字定義)?
  • 我還讀到了在執行線程首次進入該塊時,使用static關鍵字在塊內(即在函數中)定義的對象已初始化! 這意味着本地靜態對象不會在執行函數之前初始化。 這意味着它們沒有被初始化為上述兩個步驟,對嗎?
  • 動態初始化是指由操作員創建的對象的初始化,對嗎? 它可能像myClass obj = myClass(100);一樣引用初始化myClass obj = myClass(100); myClass obj = foo();

我對初始化和存儲類說明符問題有太多咨詢。 我閱讀了C ++ 2003 Standard文檔,但找不到清晰的邏輯,因為它們分散在整個文檔中。

我希望您能給我一個答案, 從邏輯上解釋存儲類說明符和初始化的整個過程。 歡迎任何參考!

可以解釋我的問題的代碼:

class myClass{
public:
   int i;
   myClass(int j = 10): j(i){}
   // other declarations
};

myClass obj1;//global scope
static myClass obj2(2);//file scope
{   //local scope
   myClass obj3(3);
   static myClass obj4(4);
}

編輯
如果您認為我的問題很繁瑣,可以根據上述代碼幫助解釋您的想法。

我從Google閱讀了有關C ++初始化的幾篇文章,其中一些將我引到StackOverflow上。 我從這些帖子中挑選的概念如下:

  • C ++的初始化順序為:
    1. 零初始化 ;
    2. 靜態初始化 ;
    3. 動態初始化

是的,確實有3個階段(在標准中)。 讓我們在繼續之前澄清它們:

  • 零初始化:存儲器在字節級別填充為0。
  • 常量初始化:將預先計算的(編譯時)字節模式復制到對象的內存位置
  • 靜態初始化:零初始化,然后進行常量初始化
  • 動態初始化:執行一個函數來初始化內存

一個簡單的例子:

int const i = 5;     // constant initialization
int const j = foo(); // dynamic initialization
  • 靜態對象 (包括變量)首先被零初始化 ,然后被靜態初始化

是的,沒有。

該標准要求首先將對象初始化為零,然后將它們初始化為:

  • 如果可能的話,初始化常量
  • 否則動態初始化(編譯器無法在編譯時計算內存內容)

注意:在進行常量初始化的情況下,編譯器可能會遵循as-if規則而忽略第一個零初始化的內存。

我有一些關於初始化問題的查詢( 存儲類問題也可能與此有關):

  • 全局對象 (未使用static關鍵字定義)也是靜態對象,對嗎?

是的,在文件范圍內, static對象只是符號的可見性 可以從另一個源文件中按名稱引用全局對象,而static對象名稱完全位於當前源文件的本地。

混亂源於在許多不同情況下對世界static的重用:

  • 全局對象也像靜態對象一樣通過上述兩個步驟初始化,對嗎?

是的,實際上是本地靜態對象。

  • 什么是靜態初始化 它是否涉及初始化靜態對象(使用static關鍵字定義)?

不,如上所述,它是指在不執行用戶定義的函數的情況下初始化對象,而是在對象的內存上復制預先計算的字節模式。 請注意,對於稍后將被動態初始化的對象,這只是將內存清零。

  • 我還讀到了在執行線程首次進入該塊時,使用static關鍵字在塊內(即在函數中)定義的對象已初始化! 這意味着本地靜態對象不會在執行函數之前初始化。 這意味着它們沒有被初始化為上述兩個步驟,對嗎?

盡管實際上只有第一次執行通過了它們的定義,但它們是通過兩步過程進行初始化的。 因此,過程相同,但時間略有不同。

但是實際上,如果它們的初始化是靜態的(即,內存模式是編譯時模式)並且不占用其地址,則可以將它們優化。

請注意,在動態初始化的情況下,如果初始化失敗(本應初始化它們的函數會拋出異常),則下一次流控制通過它們的定義時,它將重新嘗試。

  • 動態初始化是指由操作員創建的對象的初始化,對嗎? 它可能像myClass obj = myClass(100);一樣引用初始化myClass obj = myClass(100); myClass obj = foo();

完全不是指需要執行用戶定義函數的初始化(注意:就C ++語言而言, std::string具有用戶定義的構造函數)。

編輯:感謝Zach指向我,我錯誤地稱靜態初始化為C ++ 11標准稱為常量初始化; 現在應該修復此錯誤。

我相信有三個不同的概念:初始化變量,變量在內存中的位置,變量的初始化時間。

第一:初始化

當在內存中分配變量時,典型的處理器會保持不變,因此該變量將具有與其他人之前存儲的值相同的值。 為了安全起見,一些編譯器添加了額外的代碼以初始化其分配為零的所有變量。 我認為這就是您所說的“零初始化”。 當您說:

 int i; // not all compilers set this to zero

但是,如果您對編譯器說:

 int i = 10;

然后編譯器指示處理器將10放入內存中,而不是保留舊值或將其設置為零。 我認為這就是您所說的“靜態初始化”。

最后,您可以這樣說:

 int i;
 ...
 ...
 i = 11;

然后處理器在執行int i;時會“歸零初始化”(或保留舊值) int i; 然后當它到達第i = 11行時,它會將變量“動態初始化”為11(第一次初始化后可能會發生很長時間。

第二:變量的位置

有:基於堆棧的變量(有時稱為靜態變量)和內存堆變量(有時稱為動態變量)。

可以使用以下方法在堆棧段中創建變量:

int i;

或像這樣的內存堆:

int *i = new int;

不同之處在於,退出函數調用后,堆棧段變量丟失,而內存堆變量則保留,直到您說出delete i;為止delete i; 您可以閱讀匯編語言書籍以更好地理解它們之間的區別。

第三:變量初始化的時間

當您輸入在其中定義的函數調用時,堆棧段變量是“零初始化的”或“靜態初始化的”。

new操作符首次創建內存堆變量時,該變量將被“零初始化”或“靜態初始化”。

最后的話

您可以考慮一下static int i; 作為一個全局變量,范圍僅限於定義它的功能static int i; 之所以會這樣,是因為“靜態聽到”意味着另一件事(退出例程時它不會被破壞,因此它保留了其價值)。 我不確定,但我認為static int i;的技巧是 是將其放入main()的堆棧中,這意味着直到您退出整個程序(它保留第一個初始化),它才會被銷毀,或者它可能存儲在應用程序的數據段中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM