簡體   English   中英

變量的作用域與生命周期

[英]Scope vs. Lifetime of Variable

變量的作用域和生命周期之間有什么關系? 如果一個變量超出范圍,它的內存是否允許被另一個變量覆蓋,或者是否保留空間直到函數離開。

我在 aksing 因為我想知道下面的代碼是否真的有效,或者 *p 是否可能是未定義的

foo() {
  int *p;
  {
    int x = 5; 
    p = &x;
  }
  int y = *p;


}

什么是范圍?

范圍是可以訪問變量的區域或代碼段。

什么是一生?

生命周期是對象/變量處於有效狀態的持續時間。

對於,自動/本地非靜態變量Lifetime僅限於它們的Scope
換句話說,一旦創建它們的作用域( { , } )結束,自動變量就會自動銷毀。 因此,名稱自動開始。

您的代碼示例有什么問題?

所以是的,你的代碼有一個Undefined Behavior

在您的示例中, *p范圍是創建后的整個函數體。
然而, x是一個非靜態局部/自動變量,因此x的生命周期以其作用域結束,即創建它的}的右大括號,一旦作用域結束x就不存在。 *p指向不再存在的東西。

請注意,技術上x不存在於其范圍之外,但是可能會發生編譯器沒有刪除x的內容,並且一個人可能能夠通過指針訪問超出其范圍的x內容(就像您所做的那樣)。但是,代碼這不是有效的 C++ 代碼。 這是一個調用未定義行為的代碼。 這意味着任何事情都可能發生(您甚至可能會看到x值是完整的),並且不應期望從這樣的代碼中可以觀察到行為。

C11 第 6.2.1 節第 2 段

對於標識符指定的每個不同實體,標識符僅在稱為其范圍的程序文本區域內可見(即,可以使用)。 由同一標識符指定的不同實體要么具有不同的作用域,要么位於不同的名稱空間中

.

C11 第 6.2.4 節第 2 段

對象的生命周期是程序執行的一部分,在此期間保證為其保留存儲空間。

在你的情況下, x是塊的本地,它的生命周期也是如此,因此x不能在塊外通過它的名字訪問,也因為它的生命周期僅限於它的塊,離開塊后x的地址將不再保留,因此將導致未定義的行為。

另一方面,例如,說一個static局部變量,在這種情況下,作用域是塊本地的,所以我們不能在塊外通過它的名字訪問,但生命周期是整個程序,所以我們可以使用程序運行時變量在程序中任何位置的地址。 這個例子應該有助於區分。

對象(即存儲值的實際底層事物)具有生命周期。

變量(即用來指代對象的東西)有作用域。

無論哪種方式, y = *p調用未定義的行為; x引用的對象是自動的,當x超出范圍時,它的生命周期結束。

變量的作用域和生命周期之間有什么關系?

正如奧利所說,變量有作用域和對象生命周期。 變量的范圍和它的生命周期是綁定的,但是你可以擁有生命周期超出創建它們的范圍的對象:

int* f() {
   int *p                    // Variable p
          = new int(1);      // object (call it x)
   return p;                 // p scope ends, p lifetime ends, x survives
}
int main() {
   int *q                    // Variable q
          = f();             // ... points to x
   delete q;                 // x lifetime ends, q is in scope, q is alive
}

在您的特定情況下, x變量在創建它的范圍關閉時結束其生命周期,因此您具有未定義的行為。

如果一個變量超出范圍,它的內存是否允許被另一個變量覆蓋,或者是否保留空間直到函數離開。

這是一個實現細節。 訪問變量在所有情況下都是未定義的行為,因為並非所有情況都必須相等,並且如果變量具有非平凡的析構函數,它將在作用域的末尾被調用,因此內存是否存在無關緊要:該對象不再存在。 也就是說,在許多情況下,當變量超出范圍時,編譯器不會釋放函數中的內存(即它們不會重新設置幀指針),但它們可能會重用相同的空間來保存同一函數中的其他變量。

我已經運行了你的程序,輸出是 5。盡管 x 變量在第二個 '}' 之后被銷毀,但輸出仍然是 5 是因為內存位置沒有被任何其他變量覆蓋。如果之后你有很多代碼第二個作用域的結尾,很可能之前由 'x' 擁有的內存位置被覆蓋了。

int x = 5; 
*p = &x;
}  //  x lifetime ends after this.but the number '5' is still there in that memory.
   //but it is possible to assign this memory (which previously belong to x) to a new var.

標准定義了一旦離開范圍就允許覆蓋內存。 編譯器實現使其保留和釋放。 編譯時優化可能會移動堆棧的分配,因此它們將不再反映您的順序。

您的代碼確實調用了未定義的行為,不應使用。 您的代碼實際上可能有效,因為在取 p 指向的值之后寫入 y 的值。

暫無
暫無

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

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