2010-05-21 18 views
15

Wiem, że zwiększenie lub kompilator powinien być ostatni, aby winić, ale nie widzę tutaj innego wyjaśnienia. Używam msvc 2008 SP1 i zwiększam 1,43.Potrzebujesz pomocy z BOOST_FOREACH/kompilatorem błędu

w kodzie następującym wykonanie urywka nigdy nie opuszcza trzeci pętla 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 

kod Iterator:

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; 
}; 

Niektóre ASM zabawa:

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 

Łatwo zauważyć, że uchwyt iteratora jest buforowany w EBP i nigdy nie jest ts inkrementowane pomimo wywołania funkcji iteratora ++().
Zastąpiłem implantację Itarra jedną ze zmiennych pochodzących ze std :: iterator, a problem nadal występował, więc nie jest to błąd iterator_facade. Ten problem występuje tylko w kompilacjach wersji msvc 2008 SP1 x86 i amd64. Debugowanie odbywa się na msvc 2008, a kompilacje debugowania/wydania na msvc 2010 i gcc 4.4 (Linux) działają bez zarzutu. Ponadto blok BOOST_FOREACH musi zostać powtórzony tylko 10 razy. Jeśli jest powtórzony 9 razy, wszystko jest w porządku.

Domyślam się, że ze względu na BOOST_FOREACH użycie szablonowego oszustwa (const auto_any), kompilator zakłada, że ​​uchwyt iteratora jest stały i nigdy nie odczytuje jego rzeczywistej wartości ponownie.

Byłbym bardzo szczęśliwy słysząc, że mój kod jest nieprawidłowy, popraw go i przejdź do BOOST_FOREACH, którego bardzo znajduję (w przeciwieństwie do BOOST_FOREVER :).

mogą być związane z: Why does BOOST_FOREACH not work sometimes with C++ strings?

EDIT:

Przygotowałem uproszczony projekt odtworzenia problemu. Bez szablonów, bez domyślnych parametrów, bez niczego. Pobierz: http://yabcok.nazwa.pl/ugly3.zip

+3

Czy możliwe byłoby zapewnienie zestawu testowego do kompilacji? Czy próbowałeś porównać kod złożenia dwóch pętli z identycznym kodem C++? Fakt, że pętlę należy powtórzyć 10 razy, sugeruje, że może to być błąd kompilatora związany z optymalizacją. –

+0

co się dzieje z 013E1392? –

+0

przeskocz do 013E1380 - początek pętli na zawsze –

Odpowiedz

1

Wygląda mi tak, jak bug in VC++ odnośnie domyślnych wartości w funkcjach szablonu.

Istnieje bardzo podobny błąd here w sierpniu 2009 r. (Zamknięty jako "poprawiony" przez M $ w ich następnym wydaniu) ... jest spójny pod wieloma względami: jest specyficzny dla VC++ i działa w GCC, powoduje sporadyczne niepowodzenie z domyślne argumenty szablonów (ale nigdy problemów z kompilacją), a problem pojawia się tylko w drugim wystąpieniu.

Powiedział, że nie może wyjaśnić wyjście kompilatora, albo magiczne 10 pętle ... :-)

VC++ ma nawet stary artykuł na workarounds with templates. z bardzo podobnymi błędami tak niedawno i jak konsekwentnie wygląda twój błąd i błąd Color_of_Green, jest to prawdopodobnie VC++, a nie Boost.

Zgaduję? To dławi w tych podpisach: const T & data = T() w graph_elements_collection.h. MSFT zaleca zmianę tego na const T data = T(). Aby sprawdzić, czy jest on związany z tym błędem kompilatora, wypróbuj to lub obejścia opublikowane przez MSFT ... here ...

+0

Ponieważ Visual C++ 2010 jest już dostępny, czy próbowałeś powtórzyć to z nowym kompilatorem, aby sprawdzić, czy problem zniknie? Jeśli tak, możesz być pewien, że to błąd, który został naprawiony. –

+0

Nie wiem, dlaczego kiedykolwiek zrobiłbyś 'const t data = T()' zamiast tylko 'const t'. – Puppy

+0

@DeadMG: Przepraszam, nie rozumiem, czy mógłbyś to rozwinąć? – Saul

2

Spróbuj dodać/Oy- flag kompilatora (Właściwości Konfiguracja -> C/C++ -> Optymalizacja -> Wyłącz "Pominąć klatek Pointer")

miałem ten sam problem przy użyciu MSVC 2010, a to rozwiązane to!

Powiązane problemy