1. 程式人生 > >C++PrimerPlus學習之記憶體模型和名稱空間

C++PrimerPlus學習之記憶體模型和名稱空間

標頭檔案

  • 如果檔名包含在尖括號中,則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;
    
  • 函式的連結性

    • 函式預設為外部靜態的 即預設是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;
    }