2017年11月06日
《その107》 静的データメンバ と 静的メンバ関数
静的データメンバ と 静的メンバ関数
新版明解C++入門編 p.475 に重要事項として次の文章が書かれています。
静的データメンバの初期化は、それを定義するソースファイル中で初めて利用される時点までに完了することになっている。main関数の実行前に初期化が完了するという保証はない。
私にはわかりにくい文章だったので、次のようなプログラムで考えてみました。
プログラム A ------------------------
// ヘッダ C.h
class C {
static int n_; // @静的データメンバの宣言
public:
C() {}
static int n() { return n_; } // A 静的メンバ関数
};
// ソースファイル C.cpp
#include "C.h"
int C::n_ = 100; // B静的データメンバの実体を定義(初期化)
// C_Test.cpp
#include <iostream>
#include "C.h"
int main() {
std::cout << C::n() << '\n'; // C
}
-------------------------------------
静的データメンバや静的メンバ関数は、クラスオブジェクトを一つも作成していない段階でも存在するので、main関数でいきなりCを実行することができます。
Cを実行するために、Aが実行されます。
ということは、プログラム A では、Bが実行されないうちに、初期化されていない 静的データメンバ n_ が呼ばれることになる可能性があるということなのだと思います。
「静的データメンバの初期化は、それを定義するソースファイル中で初めて利用される時点までに完了することになっている」
初期の段階で、ソースファイル中で静的データメンバ n_ が利用されるようにするために、上のプログラムで、静的メンバ関数の定義Cをソースファイル中に移動させて、プログラム B のようにすればよさそうです。
プログラム B ------------------------
// ヘッダ C.h
class C {
static int n_; // @静的データメンバの宣言
public:
C() {}
static int n(); // A 静的メンバ関数の宣言
};
// ソースファイル C.cpp
#include "C.h"
int C::n_ = 100; // B静的データメンバの実体を定義(初期化)
int C::n() { return n_; } // D 静的メンバ関数の定義
// C_Test.cpp
#include <iostream>
#include "C.h"
int main() {
std::cout << C::n() << '\n'; // C
}
-------------------------------------
Aでは、関数 n() の宣言だけにしておいて、定義は、Dの位置で定義するようしました。
このようにすれば、静的メンバ関数の定義は初期の段階で行われますから、その初期の時点で、ソースファイル中の n_ が初めて利用されるので、そのさらに前に n_ の初期化が完了することになります。
つまり、main関数の実行前に初期化が完了することが保証されるということになるのではないでしょうか。
新版明解C++入門編 p.475 の重要事項の文章を、私としては、以上のように理解してみました。
※ ただし、実際には、最初のプログラム A も問題なく動きました。「main関数の実行前に初期化が完了」していない可能性があるということだと思います。
--
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/6939679
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック