2010-05-21 4 views
15

부스트 또는 컴파일러가 마지막으로 비난해야한다는 것을 알고 있지만 다른 설명은 여기에서 볼 수 없습니다. 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

+3

컴파일 가능한 테스트 케이스를 제공 할 수 있습니까? 또한 동일한 C++ 코드로 두 루프의 어셈블리 코드를 비교해 보았습니까? 루프가 10 번 반복되어야한다는 사실은 이것이 최적화 관련 컴파일러 버그 일 수 있음을 암시합니다. –

+0

013E1392는 어떻게됩니까? –

+0

013E1380으로 점프 - 영원히 시작되는 루프 –

답변

1

저의 모습은 템플릿 기능의 기본값 인 bug in VC++과 같습니다.

2009 년 8 월에 매우 유사한 버그 here (다음 릴리스에서 M $에 의해 '고정'으로 마감 됨) ... 수많은 방법으로 일관성이 있습니다. VC++에 고유하며 GCC에서 작동하여 간헐적으로 실패합니다. 기본 템플릿 인수 (그러나 컴파일 타임 문제는 없음)이며 문제는 두 번째 인스턴스화시에만 나타납니다. 말했다

, 나는 심지어 workarounds with templates에 오래된 기사를 가지고 컴파일러 출력, 또는 마법 (10 개) 루프 ... :-)

VC++를 설명 할 수 없다. 매우 비슷한 버그가 최근에 있었고 버그와 Color_of_Green의 버그가 얼마나 일관성이 있는지 알 수 있습니다. 아마도 Boost가 아닌 VC++ 일 것입니다.

내 생각 엔? 이 서명들에 질식하고 있습니다 : const T & data = T() in graph_elements_collection.h. MSFT는이를 const T data = T()으로 변경할 것을 권장합니다. 이 컴파일러 버그와 관련이 있는지 확인하려면 MSFT에서 게시 한 해결 방법을 사용하십시오. here ...(-> C/C++ -> 최적화 - 구성 속성> 안 함 "프레임 포인터를 생략")

+0

Visual C++ 2010을 사용할 수 있으므로 문제가 사라지는지 확인하기 위해 최신 컴파일러에서이 작업을 반복 해 보았습니까? 그렇다면 당신은 그것이 고정 된 버그라는 것을 꽤 확신 할 수 있습니다. –

+0

왜'const t' 대신에'const t data = T()'를 사용했는지 확신 할 수 없습니다. – Puppy

+0

@DeadMG : 죄송합니다. 이해가 안됩니다. 자세히 설명해 주시겠습니까? – Saul

2

시도는/Oy- 컴파일러 플래그를 추가하는

내가 MSVC 2010 사용하여 동일한 문제가되었고, 이것이 해결 그것!