부스트 또는 컴파일러가 마지막으로 비난해야한다는 것을 알고 있지만 다른 설명은 여기에서 볼 수 없습니다. msvc 2008 SP1을 사용하고 1.43을 향상시킵니다. 다음 코드 실행에BOOST_FOREACH/compiler bug 도움이 필요하십니까
결코 떠나지 않는다 세 번째 BOOST_FOREACH 루프
typedef Graph<unsigned, unsigned>::VertexIterator Iter;
Graph<unsigned, unsigned> g;
g.createVertex(0x66);
// works fine
Iter it = g.getVertices().first, end = g.getVertices().second;
for(; it != end; ++it)
;
// fine
std::pair<Iter, Iter> p = g.getVertices();
BOOST_FOREACH(unsigned handle, p)
;
// fine
unsigned vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
vertex_count++;
// oops, infinite loop
vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
vertex_count++;
vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
vertex_count++;
// ... last block repeated 6 times
반복자 코드 :
class Iterator
: public boost::iterator_facade<Iterator, unsigned const,
boost::bidirectional_traversal_tag>
{
public:
Iterator()
: list(NULL), handle(INVALID_ELEMENT_HANDLE)
{}
explicit Iterator(const VectorElementsList &list, unsigned handle = INVALID_ELEMENT_HANDLE)
: list(&list), handle(handle)
{}
friend std::ostream&
operator<<(std::ostream &s, const Iterator &it)
{
s << "[list: " << it.list <<", handle: " << it.handle << "]";
return s;
}
private:
friend class boost::iterator_core_access;
void increment()
{
handle = list->getNext(handle);
}
void decrement()
{
handle = list->getPrev(handle);
}
unsigned const& dereference() const
{
return handle;
}
bool equal(Iterator const& other) const
{
return handle == other.handle && list == other.list;
}
const VectorElementsList<T> *list;
unsigned handle;
};
일부 ASM 재미 :
vertex_count = 0;
BOOST_FOREACH(unsigned handle, g.getVertices())
// initialization
013E1369 mov edi,dword ptr [___defaultmatherr+8 (13E5034h)] // end iterator handle: 0xFFFFFFFF
013E136F mov ebp,dword ptr [esp+0ACh] // begin iterator handle: 0x0
013E1376 lea esi,[esp+0A8h] // begin iterator list pointer
013E137D mov ebx,esi
013E137F nop
// forever loop begin
013E1380 cmp ebp,edi
013E1382 jne main+238h (13E1388h)
013E1384 cmp ebx,esi
013E1386 je main+244h (13E1394h)
013E1388 lea eax,[esp+18h]
013E138C push eax
// here iterator is incremented in ram
013E138D call boost::iterator_facade<detail::VectorElementsList<Graph<unsigned int,unsigned int>::VertexWrapper>::Iterator,unsigned int const ,boost::bidirectional_traversal_tag,unsigned int const &,int>::operator++ (13E18E0h)
013E1392 jmp main+230h (13E1380h)
vertex_count++;
// forever loop end
는 것을 쉽게 알 수 iterator 핸들이 EBP에 캐시되고 결코 생성되지 않습니다. 반복 연산자 ++() 함수를 호출 함에도 불구하고 점차 증가합니다.
Itarator implmentation을 std :: iterator에서 파생 된 것으로 대체했으며 문제가 지속되어 iterator_facade 오류가 아닙니다. 이 문제는 msvc 2008 SP1 x86 및 amd64 릴리스 빌드에만 존재합니다. 디버그는 msvc 2008에서 빌드하고 디버그/릴리스 빌드는 msvc 2010 및 gcc 4.4 (linux)에서 잘 작동합니다. 또한 BOOST_FOREACH 블록을 exacly 10 번 반복해야합니다. 9 번에 걸쳐 다시 칠해도 괜찮아.
템플릿 trickery (const auto_any)를 BOOST_FOREACH로 사용하기 때문에 컴파일러는 iterator 핸들이 상수이고 실제 값을 다시 읽지 않는다고 가정합니다.
나는 내 코드가 잘못되었다는 소식을 듣고 그것을 바로 잡아서 매우 기쁘게 생각한다. (나는 BOOST_FOREVER와는 반대로) BOOST_FOREACH로 옮겨 갔다. Why does BOOST_FOREACH not work sometimes with C++ strings?
편집 :
가 관련이있을 수 있습니다 내가 문제를 재현 프로젝트를 간단하게 준비했습니다
. 템플릿 없음, 기본 매개 변수 없음, 아무 것도 없음. 그것을 얻으십시오 : http://yabcok.nazwa.pl/ugly3.zip
컴파일 가능한 테스트 케이스를 제공 할 수 있습니까? 또한 동일한 C++ 코드로 두 루프의 어셈블리 코드를 비교해 보았습니까? 루프가 10 번 반복되어야한다는 사실은 이것이 최적화 관련 컴파일러 버그 일 수 있음을 암시합니다. –
013E1392는 어떻게됩니까? –
013E1380으로 점프 - 영원히 시작되는 루프 –