簡體   English   中英

什么使靜態變量只初始化一次?

[英]What makes a static variable initialize only once?

我注意到如果在代碼中初始化C ++中的靜態變量,初始化僅在您第一次運行該函數時運行。

這很酷,但是如何實現? 它是否轉化為某種扭曲的if語句? (如果給出一個值,那么..)

void go( int x )
{
    static int j = x ;
    cout << ++j << endl ; // see 6, 7, 8
} 

int main()
{
    go( 5 ) ;
    go( 5 ) ;
    go( 5 ) ; 
}

是的,它通常會轉換為帶有內部布爾標志的隱式if語句。 因此,在最基本的實現中,您的聲明通常會轉換為類似的內容

void go( int x ) {
  static int j;
  static bool j_initialized;

  if (!j_initialized) {
    j = x;
    j_initialized = true;
  }

  ...
} 

最重要的是,如果您的靜態對象具有非平凡的析構函數,則該語言必須遵循另一個規則:這些靜態對象必須按其構造的相反順序進行破壞。 由於構造順序僅在運行時已知,因此銷毀順序也在運行時定義。 因此,每次使用非平凡的析構函數構造本地靜態對象時,程序必須將其注冊到某種線性容器中,以后它將用於按正確的順序銷毀這些對象。

不用說,實際細節取決於實施。


值得補充的是,當涉及使用編譯時常量初始化的“原始”類型的靜態對象(如示例中的int )時,編譯器可以在啟動時自由初始化該對象。 你永遠不會注意到差異。 但是,如果您使用“非原始”對象采用更復雜的示例

void go( int x ) {
  static std::string s = "Hello World!";
  ...

然后上面使用if方法是你應該期望在生成的代碼中找到的,即使用編譯時常量初始化對象。

在您的情況下,初始化程序在編譯時是未知的,這意味着編譯器必須延遲初始化並使用隱式if

是的,編譯器通常會生成一個隱藏的布爾值“這已被初始化了嗎?” 標志和每次執行該函數時運行的if

這里有更多的閱讀材料: 編譯器如何實現靜態變量初始化?

雖然它確實是“某種扭曲的”,但扭曲可能比你想象的還要多......

ZoogieZork對AndreyT答案的評論涉及一個重要方面:靜態局部變量的初始化 - 在某些編譯器上包括GCC - 默認是線程安全的 (編譯器命令行選項可以禁用它)。 因此,它使用一些線程間同步機制(某種互斥或某種原子操作),這種機制可能相對較慢 如果你不熟悉 - 性能明智 - 在你的函數中明確使用這樣的操作,那么你應該考慮是否有一個影響較小的替代變量的懶惰初始化(即你自己以線程安全的方式明確地構造它)某處只有一次)。 很少有功能對性能非常敏感,但這很重要 - 不要讓它破壞你的一天,或者讓你的代碼更復雜,除非你的程序太慢而你的探測器指的是那個區域。

它們只被初始化一次,因為這是C ++標准所要求的。 如何發生這完全取決於編譯器供應商。 根據我的經驗,編譯器會生成並使用本地隱藏標志。

暫無
暫無

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

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