Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How come the definition order is not followed when defining static member variables?

I know about the problem of the order of initialization of static variables from different translation units. However, my problem is within one translation unit and, in fact, within one struct:

template <int size>
struct SlidingTile {
    using AllActions = std::array<int, size>;
    using AllMDDeltas = std::array<int, size>;

    int mdDelta(int i) const {
        return mdDeltas_[i];
    }

    static AllActions computeAllActions() {
        std::cout << "computeAllActions" << std::endl;
        AllActions res;
        for (int i = 0; i < size; ++i) res[i] = i;
        return res;
    }

    static AllMDDeltas computeAllMDDeltas() {
        std::cout << "Entered computeAllMDDeltas" << std::endl;
        AllActions res;
        for (int i = 0; i < size; ++i) res[i] = 10 * allActions_[i];
        std::cout << "Exiting computeAllMDDeltas" << std::endl;
        return res;
    }

private:
    static const AllActions allActions_;
    static const AllMDDeltas mdDeltas_;
};

template <int size>
const typename SlidingTile<size>::AllActions
    SlidingTile<size>::allActions_ = SlidingTile<size>::computeAllActions();

template <int size>
const typename SlidingTile<size>::AllMDDeltas
    SlidingTile<size>::mdDeltas_ = SlidingTile<size>::computeAllMDDeltas();

int main() {
    SlidingTile<3> s;
    std::cout << s.mdDelta(2) << std::endl;
    return 0;
}

The output is:

Entered computeAllMDDeltas
Exiting computeAllMDDeltas
computeAllActions

To my surprise, computeAllMDDeltas gets called before computeAllActions and so allActions_ is not initialized when it is used in computeAllMDDeltas. Interestingly, computeAllActions is not called even when allActions_ is used in computeAllMDDeltas.

Why does this happen and what is the advised way in this situation?

like image 420
AlwaysLearning Avatar asked Feb 13 '17 14:02

AlwaysLearning


Video Answer


1 Answers

How come the definition order is not followed when defining static member variables?

Because the standard says that the initialization is unordered:

[basic.start.init] /2 (N4140 standard draft)

... Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization. ...


what is the advised way in this situation?

Same as initialization across translation units: Construct On First Use idiom:

struct SlidingTile {
    // ...
private:
    static const AllActions& allActions() {
        static const AllActions instance = computeAllActions();
        return instance;
    }
    static const AllMDDeltas& mdDeltas() {
        static const AllMDDeltas instance = computeAllMDDeltas();
        return instance;
    }
};
like image 123
eerorika Avatar answered Sep 29 '22 07:09

eerorika