close

轉錄至https://www.inside.com.tw/2015/01/13/coder-hacker-and-architect

在C++中,static有很多不同的意思,打字猴也常遇到static相關的問題(多半是名詞解釋),所以在這篇文章中做一個整理:

1. static修飾local variables
表示該local variable的lifetime和整個程式一樣長,但是scope卻只在該function裡面。
打字猴曾遇到的問題如下,請問這段程式執行後的印出結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;
 
void Foo() {
    static int a = 0;
    cout << a;
    ++a;
}
 
void main() {
    for (int i = 0; i < 5; ++i) {
        Foo();
    }
}

印出的結果為:01234

2. static修飾global variables
表示該global variable的scope被限制在該translation unit中,無法從其他translation unit中access到該global variable。
我們來看一個例子:
===== In a.cpp =====

1
int g_a = 566; //external linkage by default

===== In b.cpp =====

1
2
3
4
5
6
7
#include <iostream>
using namespace std;
 
void main() {
    extern int g_a;
    cout << g_a;
}

宣告在a.cpp的變數g_a是external linkage by default,所以打字猴可以在b.cpp中透過extern關鍵字來access到它,以上範例會印出566。

但是如果我們把上面範例的g_a用static來修飾:
===== In a.cpp =====

1
static int g_a = 566; //external linkage by default

===== In b.cpp =====

1
2
3
4
5
6
7
#include <iostream>
using namespace std;
 
void main() {
    extern int g_a;
    cout << g_a;
}

在編譯時就會發生以下Error (with VS 2013 Express)
Source.obj : error LNK2001: unresolved external symbol “int g_a” (?g_a@@3HA)

因為我們已經限制了g_a的scope,無法在另一個translation unit中access到它。

3. static修飾global functions
同global variables。
但打字猴要提醒的是,在C++ standard中建議以unnamed namespace來取代static global variable/function,我們會在另一篇文章中討論這件事。

4. static修飾class fields
表示該static class field的lifetime整個程式一樣長,其scope則是看它的access level;每個class的instance會共用同一個static class field的instance。

我們來看一個例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;
 
class CFoo {
public:
    void Bar() { cout << _data << endl; }
    static void Bear() { cout << _data << endl; }
    void Fuzzy(int d) { _data = d; }
private:
    static int _data;
};
 
int CFoo::_data = 183;
 
void main() {
    CFoo f1;
    f1.Bar();
    f1.Bear();
   
    CFoo f2;
    f2.Fuzzy(5566);
 
    f1.Bar();
    f1.Bear();
}

以上範例的結果會印出:
183
183
5566
5566

我們可以發現,non-static method和static method都可以access到打字猴定義的static int _data。而f1和f2這2個不同的instance共用同一個static int _data。另外值得一提的是,我們在class的外面來初始化int CFoo::_data = 183;,static class member的初始化請看這篇文章

5. static修飾class methods
表示該static class method沒有implicit this argument(表示它不能access non-static class member);不用class instance就可以invoke它。但是static class method有class的scope(取決於它的access level)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;
 
class CFoo {
public:
    CFoo(int d) : m_data(d) {}
    static void Bar() { cout << "Bar" << endl; }
private:
    int m_data;
};
 
void main() {
    CFoo::Bar();
}

在上面範例中可以發現,打字猴不用CFoo的instance就可以呼叫Bar()。

1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
 
class CFoo {
public:
    CFoo(int d) : m_data(d) {}
    static void Bear() { cout << m_data << endl; }
private:
    int m_data;
};

當打字猴打算在static class method Bear()中access m_data時,會出現以下compile error
error C2597: illegal reference to non-static member ‘CFoo::m_data’

我們可以發現static關鍵字在修飾不同東西時,會代表不同的意思。這也是C++ standard中建議以unnamed namespace來取代static global variable/function的原因之一。

最後值得一提的是,static global variable和static local variable如果沒有給初值的話,compiler會自動給0當初值;但是如果是一般的local variable沒有給初值的話,不同的compiler會有不同的behavior。(但是best practice還是在init時要給初值,避免程式的執行不如預期,也可以增加可讀性。)

1
2
3
4
5
6
7
8
9
static int g_var;
 
void main()
{
    static int s_var;
     
    cout << g_var << endl;
    cout << s_var << endl;
}

以上程式執行的結果為:
0
0

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 LiLun 的頭像
    LiLun

    LiLun の 分享平台

    LiLun 發表在 痞客邦 留言(0) 人氣()