Я работаю над частным проектом, у них есть свое собственное содержимое и шаблоны, есть итератор цикла, который они использовали для цикла 'for', выглядит следующим образом:
template<class T> class FakeLoopIter
{
public:
inline FakeLoopIter(const array<T>& from)
: m_Curr(((array<T>&)from).begin()),
m_End(from.end())
{
}
inline FakeLoopIter(const const_array<T>& from)
: m_Curr(((const_array<T>&)from).begin()),
m_End(from.end())
{
}
inline void operator++()
{
++m_Curr;
}
inline void operator++(int)
{
++m_Curr;
}
inline T* current()
{
return m_Curr;
}
inline const T* end()
{
return m_End;
}
inline operator T* ()
{
return m_Curr;
}
inline ubiBool finished() const
{
return m_Curr == m_End;
}
private:
T* m_Curr;
const T* m_End;
};
Есть функция, использующая этот циклитератор, как показано ниже:
void SampleClass::foo()
{
int lastLength = 0;
for(FakeLoopIter<MyCustomClass *> it(m_array); !it.finished(); ++it)
{
(*it)->doSomething(this);
if( (it+1) != it.end()) //optimized out
{
OwnerType src = (*it)->getOwnerInstance();
OwnerType dst = (*(it+1))->getOwnerInstance();
lastLength = (src-dst).getLength();
}
else
{
lastLength = getLastLengthSafely();
}
(*it)->setLength( lastLength );
}
}
После включения оптимизации / O2 логика 'it + 1! = it.end ()' оптимизирована (компилятор считает, что это всегда так), что приводит к сбою.
Если я изменю код, как показано ниже, он будет работать нормально:
void SampleClass::foo()
{
int lastLength = 0;
for(FakeLoopIter<MyCustomClass *> it(m_array); !it.finished(); ++it)
{
(*it)->doSomething(this);
MyCustomClass* dest = *(it + 1);
if(dest != *(it.end()))
{
OwnerType posSource = (*it)->getOwnerInstance();
OwnerType posDest = dest->getOwnerInstance();
lastLength = (posSource-posDest).getLength();
}
else
{
lastLength = getLastLengthSafely();
}
(*it)->setLength( lastLength );
}
}
Буду очень признателен, если кто-нибудь подскажет мне за этим правило оптимизации.
Если что-то неясно по этим вопросам, пожалуйста, дайте мне знать, чтобы я мог их улучшить.
PS: Кстати, я говорю о компиляторе clang.