我用自定義迭代器編寫了一個自定義容器。由於容器的特定功能,迭代器必須被懶惰地評估。對於這個問題的緣故代碼的相關部分是迭代的對其操作它以這種方式實現編譯器優化打破了懶惰的迭代器
template<typename T>
struct Container
{
vector<T> m_Inner;
// This should calculate the appropriate value.
// In this example is taken from a vec but in
//the real use-case is calculated on request
T Value(int N)
{ m_Inner.at(N); }
}
template<typename T>
struct Lazy_Iterator
{
mutable pair<int, T> m_Current;
int Index
Container<T>* C
Lazy_Iterator(const Container& Cont, int N):
m_Current{Index, T{}}, Index{N}, C{&Cont}
{ }
pair<int, T>&
operator*() const // __attribute__((noinline)) (this cures the symptom)
{
m_Current.first = Index; /// Optimized out
m_Current.second = C->Value(Index); /// Optimized out
return m_Current;
}
}
因爲迭代器本身是一個模板,它的功能可以自由通過編譯器內聯。
當我沒有優化編譯代碼時,返回的值按預期更新。當我使用發佈編譯器優化(在GCC 4.9中爲-O2)時,在某些情況下,即使m_Current成員標記爲可變,編譯器也會優化我標記爲優化出的的行。因此返回值與迭代器應該指向的值不匹配。
這是預期的行爲?你知道任何可移植的方式來指定該函數的內容應該被評估,即使它被標記爲const嗎?
我希望這個問題足夠詳盡,有用。如果在這種情況下更多細節可能會有所幫助,請諮詢。
編輯:
要回答一個評論,這是從一個小的測試程序採取了潛在的使用:
Container<double> myC;
Lazy_Iterator<double> It{myC, 0}
cout << "Creation: " << it->first << " , " << it->second << endl;
auto it2 = it;
cout << "Copy: "<< it2->first << " , " << it2->second << endl;
cout << "Pre-increment: " << (it++)->first << " , " << it->second << endl;
cout << "Post-increment: " << (++it)->first << " , " << it->second << endl;
cout << "Pre-decrement: " << (it--)->first << " , " << it->second << endl;
cout << "Post-decrement: " << (--it)->first << " , " << it->second << endl;
cout << "Iterator addition: " << (it+2)->first << " , " << (it+2)->second << endl;
cout << "Iterator subtraction: "<< (it-2)->first << " , " << (it-2)->second << endl;
reverse_iterator<Lazy_Iterator> rit{it};
cout << "Reverse Iterator: " << rit->first << " , " << rit->second << endl;
auto rit2 = rit;
cout << "Reverse Iterator copy: " << rit2->first << " , " << rit2->second << endl;
cout << "Rev Pre-increment: " << (rit++)->first << " , " << rit->second << endl;
cout << "Rev Post-increment: " << (++rit)->first << " , " << rit->second << endl;
cout << "Rev Pre-decrement: " << (rit--)->first << " , " << rit->second << endl;
cout << "Rev Post-decrement: " << (--rit)->first << " , " << rit->second << endl;
cout << "Rev Iterator addition: " << (rit+2)->first << " , " << (rit+2)->second << endl;
cout << "Rev Iterator subtraction: "<< (rit-2)->first << " , " << (rit-2)->second << endl;
測試結果是否如預期般對所有測試除了最後兩行
開啓優化時,測試的最後兩行發生故障。
該系統實際上運行良好,並不比其他迭代器更危險。當然,如果容器在他的鼻子下被刪除,它可能會失敗,並且通過複製使用返回的值可能會更安全,而不僅僅是保留參考,但這是脫離主題
這是一個很好的問題,但是您認爲您可以編輯代碼片段來獲取錯別字嗎? – Bathsheba
你指的是哪種拼寫錯誤?我改變了我忘記替換的typedefs的類型。如果有更多,請讓我知道 – Triskeldeian
你能提供[mcve]嗎?目前在問題中的代碼看起來是正確的。 – Angew