背景
C++におけるクラスの静的メンバーは、すべてのオブジェクトに共通の値や関数を特定のクラスのインスタンスに結びつけずに保持するために導入されました。これは例えば、カウンタ、オブジェクトファクトリ、または補助関数を保持するのに便利です。
問題点
常に課題だったのは、こうしたメンバーのスコープと初期化のタイミングで、特にプログラムに多くのソースファイルがある場合です。staticメンバーの不適切な定義はリンカエラーを引き起こします。
解決策
C++では、staticメンバーはクラスの定義内で宣言されますが、初期化(変数の場合)はcppファイル内で別々に行う必要があります(C++17以前)。C++17では、constexprの場合は宣言の中で直接初期化が可能です。
コードの例:
class MyClass { public: static int counter; static void increment() { ++counter; } }; int MyClass::counter = 0; // クラスの外での初期化は必須
主な特徴:
cppファイルでstaticメンバーを定義しないとどうなりますか?
リンカエラーが発生します。静的変数は宣言されますが未定義のままになるためです。ただし、static const intがconstexpr値のためにクラス内で直接初期化されている場合は例外です。
// .h class A { public: static int x; }; // .cpp // int A::x = 0; // コメントアウトされている場合 - エラーが発生します
静的関数から非静的関数を呼び出せますか?
いいえ。静的関数はthisポインタや非静的メンバーに直接アクセスできません。特定のオブジェクトへのアクセスが必要です。
class B { int data; static void foo() { // data = 3; // エラー } };
静的変数はすべてのインスタンスで共通ですか?
はい、同じ実行ファイルおよびプロセス内では、すべてのインスタンスで同じ値になります。
チームがcppファイル内でstaticメンバーを定義し忘れたため、プロジェクトが時折エラーでビルドされ、時にはインライン初期化を使用している(すべてのコンパイラでない)場合に「神秘的」な実行エラーが発生します。
利点:
欠点:
会社では、各クラスのstaticメンバーは常にcppファイル内で定義されるというルールがあります。スレッドセーフのためにstd::mutexまたはアトミック操作が使用されます。
利点:
欠点: