static

介紹

static 關鍵字可以用在兩種地方, 一個是 class 內用於宣告不用榜定 instance 的 class method 和 class member, 一個是 class 外用於宣告會在程式一啟動就建立並在程式結束收回的變數。

在 class 內使用

// static 只要加在宣告時即可

class X {
public:
    static void f();
    const static int n = 1;
    const static int m {2};     // since C++11
    const static int k;
};
const int X::k = 42;
void X::f() { std::cout << X::k << std::endl; }

如果和 constexpr 結合就必須寫好 initiailizer, 範例:

class X {
public:
    constexpr static int arr[] = { 1, 2, 3 };           // OK
    constexpr static std::complex<double> n = {1, 2};   // OK
    constexpr static int k;     // Error: constexpr static requires an initializer
};

在 class 外使用

物件的生命週期可以區分為四種:

  • automatic
    • 某個 code block 內

    • 除了宣告為 static、extern、thread_local 外的 local 物件都是屬於這種

  • static
    • 跟程式的存活時間一樣長

    • 所有在 namespace scope 宣告的物件加上標為 static 或 extern 的物件都屬於這種

  • thread (從 C++11 開始)
    • 跟 thread 的存活時間一樣長

    • 每個 thread 有各自的 instance

    • 只有標為 thread_local 的物件屬於這種

    • 可以搭配 static 和 extern 來控制 linkage

  • dynamic
    • 藉由 dynamic memory allocation 的方式來建立的物件

Linkage 狀態可以分成三種:

  • no linkage
    • 只有在同個 scope 內才能存取

    • 包含沒有標為 extern 的變數

    • 包含 local class 和其 member function

    • 包含在 block scope 宣告的名字,例如 typedef、enumerations、enumerations

  • internal linkage
    • 在同個 translation unit 內的所有 scope 都可以存取

    • 包含標為 static 的變數、函式

    • 包含沒有宣告標為 volatile、inline、extern 的 const 變數(包含 constexpr)

    • 包含 anonymous unions 內的 member

    • 包含 unnamed namespace 內的所有名稱(包含 unnamed namespace 內的 namespace)(從 C++11 開始)

  • external linkage
    • 可以在不同 translation unit 內的 scope 存取,來自其他程式語言的 translation unit 也可以存取

    • namespace 內(外層本身和外層不是 unnamed namespace):
      • 任何標上 extern 的變數

      • 沒有標為 static 的函式

      • namespace scope 沒有標上 static 的非 const 變數

      • enumerations 和 enumerators

    • block scope:
      • 標為 extern 的變數

      • 函式

以上可以注意到 static 可以改變物件的生命週期和 linkage, 標上 static 的物件的生命週期會是 static, linkage 會是 internal。

範例一:

int func() {
    static int x = 0;
    return x++;
}

範例二:

// example-file1.cpp

extern void func();

int main() {
    func();
    return 0;
}
// example-file2.cpp

class X {
public:
    static void funcx() {};
};

namespace N {
    class Y {
    public:
        static void funcy() {};
    };
}

void func() {
    X::funcx();
    N::Y::funcy();
}