2017-02-13 101 views
5

我知道來自不同翻譯單元的靜態變量的初始化順序問題。不過,我的問題是一個翻譯單元內,事實上,一個結構內:定義靜態成員變量時,未遵循定義順序?

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; 
} 

輸出是:

Entered computeAllMDDeltas 
Exiting computeAllMDDeltas 
computeAllActions 

令我驚訝的是,computeAllMDDeltascomputeAllActions之前調用等allActions_不在computeAllMDDeltas中使用時初始化。有趣的是,即使在computeAllMDDeltas中使用allActions_,也不會調用computeAllActions

爲什麼會發生這種情況,在這種情況下建議的方式是什麼?

+1

其中'computerAllMDDeltas'使用'allActions_'顯然不是無關緊要的一點 - 但你還是刪除它。請給我們一個[mcve] - 這對你來說有點幫助,但是因爲你是有問題的人,這似乎是合理的。 –

+0

您是否確定*'computeAllMDDeltas'正在使用'allActions_'?你能否更新代碼來提供一些關於使用的想法。 –

+2

請注意'allActions_'和'mdDeltas_'的定義是**模板**的定義,而不是對象的定義。 'SlidingTile <2, 3> :: allActions_'和'SlidingTile <2, 3> :: mdDeltas_'沒有明確的定義。 –

回答

5

在定義靜態成員變量時,定義順序沒有被遵循?

因爲標準說初始化是無序:

[basic.start.init/2(N4140標準草案)

...明確專門的模板類靜態的定義數據成員已經命令初始化。其他 類模板靜態數據成員(即,隱含或顯式實例化的專業化)具有無序 初始化。 ...


什麼是在這種情況下,建議的方式?

同跨翻譯單元初始化:構建在第一次使用成語:

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; 
    } 
}; 
+0

我正確地認爲,一旦這些函數的調用被內聯,使用這種技術就沒有任何開銷了? – AlwaysLearning

+0

@AlwaysLearning如果程序使用多線程支持進行編譯,則會有一些開銷。初始化必須進行同步,以防止多個線程同時調用該函數時可能發生的爭用情況。 – user2079303

+0

另外,你是否意味着使用'static const'(即'static'被錯誤省略?)來防止每次調用相應函數時重新計算這些變量? – AlwaysLearning