c++関数内部で使えるstatic変数と通常のstatic変数の違い。

# C++で使える関数内のstatic
c++では関数内部でstatic変数を宣言することができます。

```c++:関数内部のstatic
void method(){
  static int count;
}
```

これの動作は、

 - 関数を利用した一回目の時だけ変数が初期化される（int変数は0で初期化される）。
 - 前回関数を使用した時の値が保持される。

というものです。

使い方によっては便利なものですが、ここで疑問を抱きました。
これは、関数内部だけの変数なのでしょうか？
staticだから、他のメソッドからもこの変数にアクセスできるんでしょうか？
あと、インスタンスを変えてもその変数は共有されているのでしょうか？

知りたくなったので検証することにしました。

# 使用したコード
以下のコードでまずコンパイルをしてみます。
まずは enum です。

```cpp:OpeCode.h
#ifndef OPECODE_H_
#define OPECODE_H_

enum OpeCode{
  ADD,    //加算
  NO_OPE, //何もしない
  PRINT,  //標準出力
};

#endif

```


```cpp:StaticTest.h
#ifndef STATICTEST_H_
#define STATICTEST_H_

#include <iostream>
#include "OpeCode.h"

using namespace std;

class StaticTest {
  private:

  public:
    StaticTest();
    void Test(OpeCode val);
    void StaticValAccess();
};

#endif
```

```StaticTest.cpp:
#include "StaticTest.h"

StaticTest::StaticTest(){

}

void StaticTest::Test(OpeCode val){
  static int count;
  if(ADD == val){
    count++;
  }else if(PRINT == val){
    cout << count << endl;
  }
}

void StaticTest::StaticValAccess(){
  cout << count << endl;
}
```

```cpp:StaticTestMain.cpp
#include "StaticTest.h"
#include "OpeCode.h"

using namespace std;

int main(){
  StaticTest a = StaticTest();
  StaticTest b = StaticTest();

  a.Test(ADD);
  cout << "printA: ";
  a.Test(PRINT);
  cout << "printB: ";
  b.Test(PRINT);

  b.StaticValAccess();
  return 0;
}
```

#### コード説明
すぐ上にある`StaticTestMain.cpp`をみていただければわかりますが、aとbのインスタンスのstatic countが共有されていれば、`a.Test(ADD);`を実行することによって`b.Test(PRINT);`と`a.Test(PRINT);`の結果は同じになるはずです。

そして、`b.StaticValAccess();`で、別の関数内部で宣言されたstatic変数にアクセスできるかどうかを試しています。

#### コンパイル

コンパイルしていきましょう。以下のコマンドでオブジェクトファイルを作っていきます。

`c++ -c StaticTest.cpp`

と、ここでコンパイルエラー出ました。以下のスクリーンショットはその中の主要な部分を抜粋したものです。
<img width="924" alt="スクリーンショット 2019-07-06 15.35.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219573/58199b51-7dc1-ff94-1d43-b0b65911cb51.png">

どうやら、**関数内部で宣言したstatic変数にはその他の関数からではアクセスできない**ようです。

ソースコードを以下のように修正してもう一度コンパイルしましょう。

```cpp:StaticTest.h
#ifndef STATICTEST_H_
#define STATICTEST_H_

#include <iostream>
#include "OpeCode.h"

using namespace std;

class StaticTest {
  private:

  public:
    StaticTest();
    void Test(OpeCode val);
    // StaticValAccessメソッドは削除
};

#endif
```

```StaticTest.cpp:
#include "StaticTest.h"

StaticTest::StaticTest(){

}

void StaticTest::Test(OpeCode val){
  static int count;
  if(ADD == val){
    count++;
  }else if(PRINT == val){
    cout << count << endl;
  }
}

// StaticValAccessメソッドは削除

```

```cpp:StaticTestMain.cpp
#include "StaticTest.h"
#include "OpeCode.h"

using namespace std;

int main(){
  StaticTest a = StaticTest();
  StaticTest b = StaticTest();

  a.Test(ADD);
  cout << "printA: ";
  a.Test(PRINT);
  cout << "printB: ";
  b.Test(PRINT);

  // b.StaticValAccess(); これも削除！
  return 0;
}
```

今度は通りました。
次は`StaticTestMain.cpp`もコンパイルしておきます

`c++ -c StaticTestMain.cpp`

これはそのままで通るはずです。

最後に作ったオブジェクトファイルをリンクさせます。実行ファイル名は`test`で生成。

`c++ -o test StaticTestMain.o StaticTest.o`

実行ディレクトリに`test`が生成されます。

それでは実行してみましょう。

`./test`

をコマンドラインから入力して実行！

<img width="759" alt="スクリーンショット 2019-07-06 15.46.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/219573/28da09c9-79e4-b792-483e-9a4a9b847113.png">

実行結果を見てみると、aインスタンス、bインスタンスのstatic countを表示した結果は、どちらも同じということがわかりますね。

どうやら、**関数内部で宣言されたstatic 変数は、インスタンスが別であっても共有されているみたいです**。

# まとめ
つまり、この検証を通してわかったのは、

・**関数内部で宣言したstatic 変数はその関数内部でしか使用することができない**

ということと、

・**ある関数内で宣言されたstatic変数は、インスタンス間で共有されている**

ということです。なかなかややこしい……。
最初はpythonの変数宣言のようなイメージなのかと思っていましたが、動作の仕方は大きく違うようですね。

クラスの関数内で宣言されたstatic変数は、通常のstatic変数と比べ、**static変数を宣言した関数内部でしか使用できないという制約がついたもの**であると言えそうです。

以上検証でした！