C++でプログラムを書いていると、「staticって何?」「どんな時に使うの?」と疑問に思ったことはありませんか?
staticは使う場所によって意味が変わるため、最初は混乱しやすいキーワードです。しかし、正しく理解すれば、メモリ効率やコードの安全性を大きく向上させることができます。
この記事を読み終えると、あなたはstaticの使い方をマスターできると思いますので、ぜひ最後まで読んでいただけると嬉しいです。
staticとは?
staticとは、「この変数や関数は特別な扱いをしますよ」と記憶域期間やスコープを制御するためのキーワードです。
C++では、staticは使う場所によって意味が変わります。
- 関数内のstatic変数: プログラム終了まで値を保持
- クラスのstaticメンバ: すべてのインスタンスで共有される
- グローバルなstatic変数・関数: そのファイル内でのみ使用可能
それぞれ詳しく見ていきましょう。
関数内のstatic変数
関数内でstatic変数を宣言すると、その変数は関数が終了しても値を保持し続けます。
▼main.cpp
#include <iostream>
void countCall() {
static int count = 0; // 初回のみ実行される
count++;
std::cout << "Called " << count << " times\n";
}
int main() {
countCall();
countCall();
countCall();
return 0;
}実行結果
Called 1 times
Called 2 times
Called 3 times
通常の変数なら毎回0に初期化されますが、static変数は値を保持し続けます。
staticを付けない場合と比較してみましょう。
▼main.cpp
#include <iostream>
void countCallNormal() {
int count = 0; // staticなし
count++;
std::cout << "Called " << count << " times\n";
}
int main() {
countCallNormal();
countCallNormal();
countCallNormal();
return 0;
}実行結果
Called 1 times
Called 1 times
Called 1 times
staticなしでは、毎回0にリセットされてしまいます。
クラスのstaticメンバ変数
クラスでstatic変数を宣言すると、すべてのインスタンスで共有される変数になります。
▼main.cpp
#include <iostream>
class Player {
public:
static int totalPlayers; // static メンバ変数
Player() {
totalPlayers++;
}
};
// static メンバ変数の定義(クラス外で必要)
int Player::totalPlayers = 0;
int main() {
std::cout << "Total: " << Player::totalPlayers << "\n";
Player p1;
std::cout << "Total: " << Player::totalPlayers << "\n";
Player p2;
std::cout << "Total: " << Player::totalPlayers << "\n";
return 0;
}実行結果
Total: 0
Total: 1
Total: 2
staticメンバ変数は、各インスタンスごとではなく、クラス全体で1つだけ存在します。
重要なポイント
- staticメンバ変数はクラス外で定義が必要
クラス名::変数名でアクセスできる- すべてのインスタンスで値を共有する
クラスのstaticメンバ関数
staticメンバ関数は、インスタンスを作らずに呼び出せる関数です。
▼main.cpp
#include <iostream>
class Math {
public:
static int add(int a, int b) {
return a + b;
}
static int multiply(int a, int b) {
return a * b;
}
};
int main() {
// インスタンスを作らずに呼び出せる
std::cout << "3 + 5 = " << Math::add(3, 5) << "\n";
std::cout << "3 * 5 = " << Math::multiply(3, 5) << "\n";
return 0;
}実行結果
3 + 5 = 8
3 * 5 = 15
staticメンバ関数は、非staticメンバ変数にアクセスできないという制限があります。
▼main.cpp
#include <iostream>
class Example {
public:
int normalVar = 10;
static int staticVar;
static void showStatic() {
std::cout << staticVar << "\n"; // OK
// std::cout << normalVar << "\n"; // エラー!
}
};
int Example::staticVar = 20;
int main() {
Example::showStatic();
return 0;
}実行結果
20
staticメンバ関数はインスタンスに紐づかないため、通常のメンバ変数にはアクセスできません。
グローバルなstatic変数・関数
ファイルのグローバルスコープでstaticを使うと、その変数や関数はそのファイル内でのみ使用可能になります。
▼sub.cpp
static int secret = 100; // このファイル内でのみ使える
static void privateFunc() {
// このファイル内でのみ呼び出せる
}▼main.cpp
#include <iostream>
// extern int secret; // エラー!他のファイルのstatic変数は使えない
int main() {
// privateFunc(); // エラー!他のファイルのstatic関数は呼べない
return 0;
}これにより、ファイル内部の実装を隠蔽できます。
モダンC++では、staticの代わりに無名名前空間(namespace)を使う方が推奨されています。
▼sub.cpp
namespace {
int secret = 100; // このファイル内でのみ使える
void privateFunc() {
// このファイル内でのみ呼び出せる
}
}【重要】私が実際にstaticで困った体験談
体験談1: 関数内でstatic付け忘れて毎回同じ値だった
大学の課題で「敵を倒した回数をカウントする関数」を作っていた時のことです。以下のようなコードを書きました。
int getEnemyCount() {
int count = 0; // staticを付け忘れ
count++;
return count;
}何度敵を倒しても「倒した敵: 1体」としか表示されず、30分以上原因がわかりませんでした。
原因は、staticを付け忘れていたこと。関数を呼ぶたびにcountが0に初期化されていました。
int getEnemyCount() {
static int count = 0; // staticを追加
count++;
return count;
}staticを追加したら正常に動作しました。関数内で値を保持したい時は、必ずstaticを付けましょう。
体験談2: staticメンバ変数の定義を忘れてリンクエラー
ゲーム制作でプレイヤー数を管理するクラスを作った時、以下のようなコードを書きました。
class Player {
public:
static int totalPlayers;
Player() { totalPlayers++; }
};
// ここに定義を書き忘れた!ビルドすると、以下のようなエラーが出ました。
error LNK2001: 外部シンボル "public: static int Player::totalPlayers" は未解決です
原因は、staticメンバ変数はクラス外で定義が必要だったこと。以下のように修正したら動きました。
class Player {
public:
static int totalPlayers;
Player() { totalPlayers++; }
};
// クラス外で定義を追加
int Player::totalPlayers = 0;この経験から、staticメンバ変数は必ずクラス外で定義することを学びました。
static使用時のよくあるエラーと対処法
エラー1: 関数内static変数が毎回リセットされる
症状: カウント変数が毎回0になってしまう
原因: staticを付け忘れている
対処法: 関数内で値を保持したい変数には必ずstaticを付けてください
// NG
void func() {
int count = 0;
count++;
}
// OK
void func() {
static int count = 0;
count++;
}エラー2: リンクエラー「外部シンボルは未解決です」
症状: error LNK2001などのリンクエラーが出る
原因: staticメンバ変数をクラス外で定義していない
対処法: クラス外で必ず定義してください
class MyClass {
public:
static int value; // 宣言
};
// クラス外で定義が必要
int MyClass::value = 0;エラー3: staticメンバ関数から通常のメンバ変数にアクセスできない
症状: error C2597: 非静的メンバへの参照が正しくありません
原因: staticメンバ関数は非staticメンバ変数にアクセスできない
対処法: アクセスしたい変数もstaticにするか、関数を非staticにしてください
class MyClass {
public:
int normalVar = 10;
static int staticVar;
static void staticFunc() {
// std::cout << normalVar; // エラー!
std::cout << staticVar; // OK
}
};実践的な使い方
staticのよくある使い方を見てみましょう。
シングルトンパターン
staticメンバを使って、クラスのインスタンスを1つだけに制限できます。
▼main.cpp
#include <iostream>
class Singleton {
private:
static Singleton* instance;
Singleton() {} // コンストラクタをprivateに
public:
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
void showMessage() {
std::cout << "Singleton instance\n";
}
};
Singleton* Singleton::instance = nullptr;
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
s1->showMessage();
// s1とs2は同じインスタンス
std::cout << (s1 == s2 ? "Same instance" : "Different instance");
return 0;
}実行結果
Singleton instance
Same instance
staticを使うべき場面
staticは以下のような場面で使います。
- 関数内static変数: 関数の呼び出し回数をカウントしたい時
- クラスのstaticメンバ変数: すべてのインスタンスで共有したいデータがある時
- クラスのstaticメンバ関数: インスタンスなしで呼び出したいユーティリティ関数
- グローバルstatic: ファイル内部の実装を隠蔽したい時(モダンC++では無名名前空間推奨)
まとめ
staticの使い方をまとめます。
- ✅ 関数内static変数: 値を保持し続ける
- ✅ クラスのstaticメンバ変数: すべてのインスタンスで共有される
- ✅ クラスのstaticメンバ関数: インスタンスなしで呼び出せる
- ✅ グローバルstatic: そのファイル内でのみ使用可能(モダンC++では無名名前空間推奨)
- ✅ staticメンバ変数はクラス外で定義が必要
- ✅ 関数内で値を保持したい時は必ずstaticを付ける
- ✅ staticメンバ関数は非staticメンバ変数にアクセスできない
これでstaticの使い方はバッチリですね!
適切な場面でstaticを活用して、より効率的なC++プログラムを書いてみてください。
ここまで読んでくださり、ありがとうございました。
この記事が皆様の学習に役立てば幸いです。


