天天看點

記憶體模型(存儲持續性、作用域和連結性)

              目錄:

  • 單獨編譯
  • 存儲持續性、作用域和連結性

一、單獨編譯

  1. 頭檔案常包含的内容:函數原型、使用#define或const定義的符号常量、結構聲明、類聲明、模闆聲明、内聯聲明。

若頭檔案中檔案名包含在尖括号中,則C++編譯器将在存儲标準頭檔案的主機系統的檔案系統中查找;若檔案包含在雙引号中,則編譯器将首先查找目前的工作目錄或源代碼目錄。

     2. 在同一個檔案中隻能将同一個頭檔案包含一次。避免方法:基于預處理器編譯指令#ifndef與#endif(編譯器将檢視這之間的内容,讓它忽略除第一次包含之外的所有内容)

二、存儲持續性、作用域和連結性

  • 自動存儲持續性:在函數定義中聲明的變量(包括函數參數)的存儲持續性為自動的。程式開始執行其所屬的函數或代碼塊時被建立,在執行完函數或代碼塊時其記憶體被釋放。
  • 靜态存儲持續性:在函數定義外定義的變量和使用關鍵字static定義的變量的存儲持續性都為靜态。(在程式運作過程中都存在)
  • 線程存儲持續性:多核處理器,讓程式能将計算放在可并行處理的不同線程中,若變量是使用關鍵字thread_local聲明的,則其生命周期與所屬線程一樣長。
  • 動态存儲持續性:用new運算符配置設定的記憶體将一直存在,直到使用delete運算符将其釋放或程式結束為止。這種記憶體的存儲持續性為動态,有時也被稱為自由存儲或堆。

五種變量存儲方式:

存儲描述 持續性 作用域 連結性 如何聲明
自動 自動 代碼塊 在代碼塊中
寄存器 自動 代碼塊 代碼塊中,關鍵字register
靜态,無連結性 靜态 代碼塊 代碼塊中,關鍵字static
靜态,外部連結性 靜态 檔案 外部 不在任何函數内
靜态,内部連結性 靜态 檔案 内部 不在任何函數内,使用static

1. 作用域描述了名稱在檔案(翻譯單元)的多大範圍可見。作用域為全局(檔案作用域)的變量在定義位置到檔案結尾之間都可用;自動變量的作用域為局部;在函數原型作用域中使用的名稱隻在包含參數清單的括号内可用;在類中聲明的成員的作用域為整個類;在名稱空間中聲明的變量的作用域為整個名稱空間;C++函數的作用域可以是整個類或整個名稱空間(包括全局的),但不能是局部的(不能在代碼塊内定義函數)。

連結性描述了名稱如何在不同單元間共享;連結性為外部的名稱可在檔案間共享,連結性為内部的名稱隻能由一個檔案中的函數共享

2. 自動存儲持續性

預設情況下,在函數中聲明的函數參數和變量的存儲持續性為自動,作用域為局部,沒有連結性。代碼塊中定義的變量的存在時間和作用域将被限制在該代碼塊内。

可以使用任何在聲明時其值為已知的表達式來初始化自動變量。

程式使用兩個指針來跟蹤棧,一個指針指向棧底—棧的開始位置,另一個指針指向堆頂—下一個可用記憶體單元,棧是後進先出的,即最後加入到棧中的變量首先被彈出。

關鍵字register建議編譯器使用CPU寄存器來存儲自動變量。

3. 靜态持續變量

C++為靜态存儲持續性變量提供了3種連結性:外部連結性(可在其它檔案中通路)、内部連結性(隻能在目前檔案中通路)、無連結性(隻能在目前函數和代碼塊中通路)

所有的靜态持續變量都有以下初始化特征:未被初始化的靜态變量的所有位都被設定成0. 這種變量被稱為零初始化的,也可對靜态變量進行常量表達式初始化和動态初始化。

4. 靜态持續性、外部連結性

連結性為外部的變量通常簡稱為外部變量,它們的存儲持續性為靜态,作用域為整個檔案。

C++提供兩種變量聲明:一是定義聲明(給變量配置設定記憶體空間),另一種是引用聲明(引用已有變量,使用關鍵字extern且不進行初始化)。

作用域解析運算符(::)放在變量名前表示使用變量的全局版本。程式越能避免對資料進行不必要的通路,就越能保持資料的完整性。通常情況下應使用局部變量。

5. 靜态持續性、内部連結性

将static限定符用于作用域為整個檔案的變量時,該變量的連結性将為内部的。連結性為内部的變量隻能在其所屬的檔案中使用;連結性為外部的正常外部變量可以在其他檔案中使用。

如檔案中定義了一個靜态外部變量,其名稱與另一個檔案中聲明的正常外部變量相同,則在該檔案中,靜态變量将隐藏正常外部變量。

在多檔案程式中,可以在一個檔案(且隻能在一個檔案)中定義一個外部變量。使用該變量的其他檔案必須使用extern聲明它。

6. 靜态存儲持續性、無連結性

将static限定符用于在代碼塊中定義的變量。其存儲持續性為靜态的。若初始化了靜态局部變量,則程式隻在啟動時進行一次初始化,之後再調用函數時将不會像自動變量那樣再次被初始化。

7. 說明符和限定符

a.存儲說明符:auto(自動類型推斷)、register(寄存器存儲,C++11中顯式的指出變量是自動的)、static、extern(引用聲明)、thread_local(指出變量的持續性與其所屬線程的持續性相同)、mutable(根據const解釋)

b.CV-限定符:const、volatile(即使程式代碼沒有對記憶體單元進行修改,其值也可能發生改變,該關鍵字的作用是改善編譯器的優化能力)

mutable:可用它指出,即使結構(或類)變量為const,其某個成員也可被修改。

c.預設情況下全局變量的連結性為外部的,但const全局變量的連結性為内部的。即在C++看來,全局const定義就像使用了static說明符一樣,這還意味着每個檔案都有自己的一組常量,而不是所有檔案共享一組常量。

d.鑒于單個const在多個檔案間共享,是以隻有一個檔案可對其進行初始化。

8. 函數和連結性

所有的函數的存儲持續性都自動為靜态的。即在整個程式執行期間一直存在。預設情況下,函數的連結性為外部的,即可在檔案間共享(可以在函數原型中使用extern)。使用static将函數的連結性設定為内部的,使之隻能在一個檔案中使用,必須同時在原型和函數定義中使用static。C++要求同一個函數的所有内聯定義都必須相同,對于每個非内聯函數,程式隻能包含一個定義。

9. 語言連結性

連結程式要求每個不同的函數都有不同的符号名。C++編譯器執行名稱矯正或名稱修飾,為重載函數生成不同的符号名稱。

繼續閱讀