C++: スコープと寿命

最終更新:2026-08-31

変数はどこで宣言するかでスコープ(どこで見えるか)と寿命(いつ存在するか)が決まる。これを理解しないと、予測不能なバグに遭遇する。


1. スコープとは何か?

(1) 1.1 定義

スコープは、変数がアクセス可能なコードの領域。

(2) 1.2 スコープの種類

種類 説明
ローカルスコープ ブロック内で宣言、ブロック内でのみ可視 関数内の変数
グローバルスコープ すべての関数の外で宣言、どこでも可視 グローバル変数
ブロックスコープ {}内で宣言、ブロック内でのみ可視 ループ内の変数
名前空間スコープ 名前空間内で宣言 std::cout


2. ローカル変数

(1) 2.1 特徴

(2) 2.2 例

CPP
#include <iostream>

void func() {
    int x = 10; // ローカル変数
    std::cout << x << std::endl;
} // xはここで破棄

int main() {
    func();
    // std::cout << x; // ❌ エラー: xはここでは見えない
    return 0;
}


3. グローバル変数

(1) 3.1 特徴

(2) 3.2 例

CPP
#include <iostream>

int counter = 0; // グローバル変数

void increment() {
    counter++;
}

int main() {
    increment();
    increment();
    std::cout << counter << std::endl; // 2
    return 0;
}
⚠️ 注意: グローバル変数は避ける。どの関数でも変更でき、バグの原因になる。どうしても必要な場合のみ使う。



4. スタティック変数

(1) 4.1 ローカルスタティック変数

関数内でstaticとして宣言。プログラム終了まで存在。

CPP
#include <iostream>

void countCalls() {
    static int calls = 0; // 初回だけ初期化
    calls++;
    std::cout << "呼び出し回数: " << calls << std::endl;
}

int main() {
    countCalls(); // 1
    countCalls(); // 2
    countCalls(); // 3
    return 0;
}

(2) 4.2 グローバルスタティック変数

ファイル内でのみ可視なグローバル変数。



5. ブロックスコープ

{}で作られるスコープ:

CPP
#include <iostream>

int main() {
    int x = 10;
    
    {
        int y = 20;
        std::cout << x << " " << y << std::endl; // OK: 両方可視
    }
    
    // std::cout << y; // ❌ エラー: yはブロック外
    return 0;
}


6. 名前の隠蔽

内側のスコープで同じ名前の変数を宣言すると、外側の変数を隠す:

CPP
#include <iostream>

int x = 100; // グローバル

int main() {
    int x = 10; // ローカルがグローバルを隠す
    std::cout << x << std::endl; // 10
    std::cout << ::x << std::endl; // 100 (::でグローバルにアクセス)
    return 0;
}

▶ サンプル 1:スタティック変数で呼び出し回数を追跡(難易度 ⭐)

CPP
#include <iostream>

void login() {
    static int loginCount = 0;
    loginCount++;
    std::cout << "ログイン回数: " << loginCount << std::endl;
}

int main() {
    login();
    login();
    login();
    return 0;
}
▶ 試してみよう

出力:

TEXT 📖 参照専用
ログイン回数: 1
ログイン回数: 2
ログイン回数: 3

▶ サンプル 2:ブロックスコープ(難易度 ⭐⭐)

CPP
#include <iostream>

int main() {
    int x = 5;
    std::cout << "外側のx: " << x << std::endl;

    {
        int x = 10; // 外側のxを隠す
        std::cout << "内側のx: " << x << std::endl;
    }

    std::cout << "また外側のx: " << x << std::endl;
    return 0;
}
▶ 試してみよう

▶ サンプル 3:グローバル変数の危険性(難易度 ⭐⭐)

CPP
#include <iostream>

int total = 0; // グローバル変数

void add(int value) {
    total += value; // グローバル変数を変更
}

void reset() {
    total = 0; // 意図しないリセットの可能性
}

int main() {
    add(10);
    add(20);
    std::cout << "合計: " << total << std::endl; // 30
    
    reset(); // 誤ってリセット
    add(5);
    std::cout << "リセット後: " << total << std::endl; // 5
    
    return 0;
}
▶ 試してみよう
⚠️ 注意: この例はグローバル変数の危険性を示している。どの関数でも変更できるため、バグの追跡が困難になる。


❓ よくある質問

Q 変数を初期化しないとどうなる?
A ローカル変数はゴミ値が入る(予測不能)。グローバル/スタティック変数は0に初期化。常に明示的に初期化しよう。
Q グローバル変数はいつ使う?
A 避ける。どうしても必要な場合(設定値、ログ、状態)にのみ使い、必要最小限に。
Q スタティック変数はどこに保存される?
A ローカルスタティック変数はグローバル変数と同様、静的メモリ(.data/.bssセグメント)に保存。関数終了後も残る。

📖 まとめ


📝 練習問題

  1. 初級(難易度 ⭐): 関数を作成し、スタティック変数を使って何回呼び出されたかを出力。

  2. 中級(難易度 ⭐⭐): ローカル変数とグローバル変数の違いを示すプログラムを書く。

  3. 上級(難易度 ⭐⭐⭐): ブロックスコープを悪用して読みにくいコードを書く。次に、同じ機能をスコープを整理して書き直す。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%