その1の続き。今度は代替方法。

「最初に初期化したい」が実際には「他のグローバル変数からいつ使われるか分からないからそれまでに初期化したい」であるのなら、シングルトンパターンでよくあるように最初に使う時に初期化すればよいことになります。ただし、この時に以下のようなコードは書けません。VEC::VEC() がいつ呼ばれるか分からないからです。

class VEC
{
public:
    std::vector<int> *v;
    VEC() { v = NULL; }
    ~VEC()
    {
        if (v != NULL) 
            delete v;
    }
    std::vector<int>& vec()
    {
        if (v == NULL)
            v = new std::vector<int>({ 1, 2 });
        return *v;
    }
} vec;
std::vector<int> other = vec.get();

初期化が動的でなければいいので、こういうのなら大丈夫なはずです。

class VEC
{
public:
    static std::vector<int> *v;
    ~VEC()
    {
        if (v != NULL) 
            delete v;
    }
    std::vector<int>& vec()
    {
        if (v == NULL)
            v = new std::vector<int>({ 1, 2 });
        return *v;
    }
} vec;

std::vector<int> *VEC::v = NULL;
std::vector<int> other = vec.get();

あるいは、こういうのでもいいかもしれません。

std::vector<int>& vec()
{
    static std::vector<int> v = { 1, 2 };
    return v;
}
std::vector<int> other = vec();

関数の static なローカル変数は、最初に実行がその行に到達した時に一度だけ初期化され、コンストラクタが呼ばれた場合にのみデストラクタが呼ばれます。なお、関数呼び出しのオーバーヘッド(処理系が頑張ってくれれば消滅する)の他に、初期化をスレッドセーフにするために排他制御するオーバーヘッドが発生します(C++11 でスレッドセーフでないといけないことになった)。

あ、でもこれデストラクタがいつ呼ばれるか分からないぞ…

その3に続く。

Trackback

only 1 comment untill now

  1. グローバル変数の初期化順序を制御する(その3)

    その2の続き。今度は条件付き。 最初に初期化したい変数(のコンストラクタ)からアプリケーションの他の部分を呼ばないのであれば、変数をライブラリに追い出すことで先に初期化…

Add your comment now