2012-11-24 59 views
1

我是正確的假設,初始化列表和std ::向前

class D { /* ... */ }; 

int f (const D & t) { return /* something calculated from t */; } 

template<class T> 
class C { 
private: 
    int m_i; 
    T m_t; 
    // or first m_t, then m_i -- careless order of declarations 
public: 
    template<class T_> 
    C (T_ && t) : m_t (std::forward<T_> (t)), m_i (f (t)) { 
    } 
}; 

C<D> c (D()); 

可能會導致一個錯誤,因爲的t價值已搬走時f(t)叫?除了(i)使用工廠功能或(ii)引入對聲明m_im_t的順序的依賴性之外,是否有任何方法可以避免此問題?

+0

重新排序聲明並使用f(m_t)'有什麼問題?這似乎也是唯一有意義的東西(想想'T'的顯式構造函數)。 –

+0

我認爲它被認爲是不好的風格和容易出錯? – JohnB

+0

好吧,你需要你所需要的。 *如果您願意,編程*很容易出錯。我根本不喜歡這個設計('f'和'T_'之間有什麼奇怪的關係?),但是如果這就是你需要的,你必須這樣做...... –

回答

3

的第一件事就是初始化列表的評估順序由類定義的成員的順序確定的,所以你的情況,這將是:

template<class T_> 
C (T_ && t) 
    : m_i (f (t)), m_t (std::forward<T_> (t)) { 
} 

所以你的情況沒事。這也將是很好,如果你重新排序,以便m_t聲明成員之前m_i和你在初始化中使用m_t

T m_t; 
int m_i; 
template<class T_> 
C (T_ && t) 
    : m_t (std::forward<T_> (t)), m_i (f (m_t)) { 
} 
+0

這不是那種糟糕的編程風格嗎? – JohnB

+2

@JohnB:我肯定會在變量定義上添加註釋,以確保它們不會重新排序。一般來說,最好避免依賴評估順序,但在這種情況下,依賴關係已經存在,一個成員的初始化取決於評估而不是另一個成員,因爲'std :: forward'可能會導致值*移動*。 –

+0

我也會寫這樣的東西,但是後來讓我覺得你的解決方案要求'T'可以轉換爲'D',而原來的只需要'T_'。所以他們有微妙的不同。雖然我不主張理解設計。 –

2

成員m_i首先初始化,由當時的價值顯然是不能移動也不會被移動。當你初始化m_t(std::forward<T>(t))時,你隱含地承諾你不會使用t的值(至少,直到你給它一個新的值)。

一般而言,執行順序很重要,成員初始化程序列表也是如此。也就是說,當你引入它們之間的依賴關係時,你需要小心你聲明你的成員的順序。

+0

對不起,當然這個想法是讓成員聲明相反,以便引入潛在的錯誤。 – JohnB