LoginSignup
10
5

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-07-06

C++で使える関数内のstatic

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

関数内部のstatic
void method(){
  static int count;
}

これの動作は、

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

というものです。

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

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

使用したコード

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

OpeCode.h
#ifndef OPECODE_H_
#define OPECODE_H_

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

#endif

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;
}
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

と、ここでコンパイルエラー出ました。以下のスクリーンショットはその中の主要な部分を抜粋したものです。
スクリーンショット 2019-07-06 15.35.22.png

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

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

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メソッドは削除

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

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

スクリーンショット 2019-07-06 15.46.23.png

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

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

まとめ

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

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

ということと、

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

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

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

以上検証でした!

10
5
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
5