C++PrimerPlus學習之記憶體模型和名稱空間
阿新 • • 發佈:2018-11-03
標頭檔案
-
如果檔名包含在尖括號中,則C++編譯器將在儲存標準標頭檔案的主機系統的檔案系統的中查詢。如果檔名包含在雙引號中,則編譯器將在當前目錄下查詢。
-
使用條件編譯防止多次包含標頭檔案
#ifndef XXX_H_ #define XXX_H_ ... #endif
儲存持續性,作用域和連結性
儲存描述 | 持續性 | 作用域 | 連結性 | 如何宣告 | 儲存位置 |
---|---|---|---|---|---|
自動 | 自動 | 程式碼塊 | 無 | 在程式碼塊中 | 棧中 |
暫存器 | 自動 | 程式碼塊 | 無 | 在程式碼塊中,使用關鍵字register | 暫存器中 |
靜態,無連結性 | 靜態 | 程式碼塊 | 無 | 在程式碼塊中,使用關鍵字static | 記憶體塊 |
靜態,外部連結性 | 靜態 | 所有檔案 | 外部 | 不在任何函式中 | 記憶體塊 |
靜態,內部連結性 | 靜態 | 本檔案 | 內部 | 不在任何函式內,使用關鍵字static | 記憶體塊 |
-
如果定義一個靜態外部連結性的變數,其他檔案在使用時,需要引用宣告使用關鍵字extern,且不進行初始化。
-
作用域解析運算子
int a=5; int main() { int a=3; cout<<a<<endl; cout<<::a<<endl;//作用域解析運算子,此時的a為全域性變數的a }
-
說明符
- register 用於在宣告中指示暫存器儲存,而在C++11中,它只是顯式地指出變數是自動的。
- static 表示內部連結性。
- extern 表面是引用宣告,即宣告引用在其他檔案定義的變數。
- thread_local(C++11新增) 指出變數的持續性與其所屬的執行緒的持續性相同。thread_local變數之於執行緒,猶如常規靜態變數之於整個程式。
- mutable 用來指出,即使結構(或類)變數為const,其某個成員也可以被修改。
struct student { char name[30]; mutable int score; }; int main() { const student a={"guo shen",100}; a.score++; cout<<a.name<<' '<<a.score<<endl; }
-
cv-限定符
- volatile
- 即使程式程式碼沒有對記憶體單元進行修改,其值也可能發生變化(可能受硬體影響)
- 如果不使用volatile變數,在再次訪問之間編譯器可能會認為值沒有變化,從而進行優化(如將值放在暫存器中快取起來)
- 使用volatile變數相當於告訴編譯器,不要進行這種優化
- const – 不能修改的記憶體
- const 對全域性變數的連結性有影響 – const全域性變數的連結性為內部的。
- 這也是const變數能寫在標頭檔案而沒有多重定義的原因
- 若想使用連結性為外部的const變數,則可以再在前面加extern進行定義,但其他檔案使用此變數必須也要用extern關鍵字進行宣告
extern const int maxn = 100;
- volatile
-
函式的連結性
- 函式預設為外部靜態的 即預設是extern的
- 可使用 static 關鍵字將其連結性設定為內部的
- 必須同時在原型和定義中使用static
- 內部靜態函式將覆蓋外部函式
-
語言連結性
- C語言對函式名的矯正使用的約定與C++不同, 可用函式原型指出其使用的約定
extern "C" void fun(int); // 使用C語言的約定 extern void fun(int); // 使用C++的約定 extern "C++" void fun(int); // 使用C++的約定 -- 顯式指出
-
動態分配記憶體
-
new運算子
void * operator new(size_t); //used by new void * operator new[](size_t);//used by new[]
-
定位new運算子
- new 負責在堆上找一塊滿足要求的記憶體塊
- 定位new 能指定要使用的位置
- 設定記憶體管理規程,處理需要通過特定地址進行訪問的硬體,在特定位置建立物件等
- 使用
#include <new> char buff[50]; int* p = new (buff) int[20]; // 從buff中分配一個包含20個int的陣列 //不能使用delete來釋放記憶體 void* operator new(std::size_t, void* position);//定位new運算子的過載
名稱空間
-
using 編譯指令和using宣告之比較
- 如果某個名稱已經在函式聲明瞭,則不能用using宣告匯入相同的名稱。
- 如果使用using編譯指令,名稱空間相當於全域性的,那麼區域性名稱將隱藏名稱空間名,就像隱藏同名的全域性變數一樣。不過仍可以使用作用域解析運算子。
-
未命名的名稱空間
namespace { int cnt=5; } //=static int cnt=5; int main() { cout<<cnt<<endl; }