2008-10-09 22 views
34

Windows ile Mac arasında bazı platformlar arası kod yazıyorum.Bir STL listesinden geriye doğru nasıl yineliyorsunuz?

Eğer liste :: end() "bir listedeki son elemanın yerini belirleyen bir adrese tekrarlayan bir yineleyici döndürür" ve bir listeyi geçerken kontrol edilebilir, geriye doğru hareket etmenin en iyi yolu nedir?

list<DVFGfxObj*>::iterator iter = m_Objs.end(); 
for (iter--; iter!=m_Objs.end(); iter--)// By accident discovered that the iterator is circular ? 
{ 
} 

bu Windows üzerinde çalışır:

list<DVFGfxObj*>::iterator iter = m_Objs.end(); 
    do{ 
     iter--; 
    } while (*iter != *m_Objs.begin()); 

o geriye çapraz başka bir yolu var mı

Bu kod (ilk elemanın ötesine azaltma olamaz) Windows üzerinde Mac ancak workson for döngüsünde uygulanabilir mi?

+1

Yalnızca ilk örneğinizin (dairesel yineleyici, bitiş() ile karşılaştırarak çalışacağı) bir uygulama kazası olurdu. – Justsalt

cevap

60

Yineleyici yerine reverse_iterator öğesini kullanın. begin() & end() yerine rbegin() &()() kullanın.

BOOST_FOREACH makrosunu kullanmak isterseniz, başka bir olanak da Boost 1.36.0'da tanıtılan BOOST_REVERSE_FOREACH makrosunu kullanmaktır.

+0

Yineleyici ve reverse_iterator belgelerine hemen hemen aynı. Bir yineleyici iki yönlüdür, bu yüzden fark nedir? – AlanKley

+2

Farkı, yineleyiciyi artırmak için "--Iter" i hala "++ Iter" yaptığınızdır. Yoksa yanılıyor muyum? – steffenj

+0

Hayır, haklısın, geriye doğru gitmenin artması biraz tuhaf ama aynı zamanda mantıklı. Yineleyicinin iki yönlü olduğu dikkate alındığında, reverse_iterator gereksiz görünüyor. Reverse_iterator için dokümanlar tersine çevrilmiş bir liste üzerinde hareket ettiğini söyler; kesinlikle önce listeyi tersine çevirmez. – AlanKley

13

Muhtemelen ters yineleyicileri istiyorsunuz. hafızasından:

list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin(); 
for(; iter != m_Objs.rend(); ++iter) 
{ 
} 
+1

Teşekkürler kulağa hoş geliyor. Ayrıca iterator çift yönlü – AlanKley

+0

olduğu varsayılırsa özel bir reverse_iterator oluşturmak için bir atık gibi görünüyor: "...> :: reverse_iterator iter = ..." – steffenj

+0

@AlanKley senin sorunun güzel. Çalıştığımın nedeni, .end() üye işlevinin, son öğeden sonraki işaretçinin değeri ve aynı zamanda ilk öğenin ön işaretçisi olarak atanmış bir sentinel değeri döndürmesidir. –

4

Daha önce Ferruccio, kullanım reverse_iterator bahsettiği:

for (std::list<int>::reverse_iterator i = s.rbegin(); i != s.rend(); ++i) 
5

Bu çalışması gerekir:

list<DVFGfxObj*>::reverse_iterator iter = m_Objs.rbegin(); 
for (; iter!= m_Objs.rend(); iter++) 
{ 
} 
16

en iyi/en kolay yolu bir listesidir yineleme ters (aynı zaten belirtilmiş) ters yineleyiciler kullanmak için rbegin/rend. Bununla birlikte, ters yineleyicilerin "geçerli" yineleyici konumunu bir kerede saklayarak (en azından standart kütüphanenin GNU uygulamasında) uygulandığını belirtmek isterim.

Bu

ileri bir aralık olarak aynı anlamlara sahip ters istikametinde aralığı için sırayla, uygulama basitleştirmek için yapılması [başlar bitiş) ve [rbegin, bunun anlamı nedir)

parçalamak bir çözümleyecek olmasıdır edilir yineleyici yeni bir geçici oluşturma ve sonra her zaman, bu azaltma içermektedir: bir reverse_iterator dereferencing Böylece

reference 
    operator*() const 
    { 
_Iterator __tmp = current; 
return *--__tmp; 
    } 

, bir normal bir yineleyici daha yavaştır.

Ancak bunun yerine bu yükü kaçınarak, kendine yineleme ters simüle etmek düzenli iki yönlü yineleyicinızı kullanabilirsiniz:

for (iterator current = end() ; current != begin() ; /* Do nothing */) 
{ 
    --current; // Unfortunately, you now need this here 
    /* Do work */ 
    cout << *current << endl; 
} 

Test ~ 5 kez kullanılan her dereference için daha hızlı olması için bu çözümü gösterdi döngünün gövdesi.

Not: Yukarıdaki kodla test yapılmadı, çünkü bu std :: cout darboğaz olurdu.

Not: 'Duvar saati saati' farkı, std :: liste boyutu 10 milyon öğeyle ~ 5 saniyeydi. Yani, gerçekçi olarak, verilerinizin büyüklüğü o kadar büyük değilse, sadece rbegin() rend() 'e yapıştırabilirsiniz!

+0

Tekrar bakın, Muhtemelen sadece current = --end(); ve döngü için artış adımını bırakın. Bu aynı zamanda benim yukarıdaki sürümün bulunmadığı boş dizilere karşı da koruyacaktır. Test edilmediğim için şimdilik yayınlanmış olan orijinali bırakacağım. – mmocny

+0

Döngü koşulunuzu değiştirmediğiniz sürece bunun işe yarayacağını düşünmüyorum. Aksi takdirde, ilk öğeyi kaçırmış olursunuz (eğer "current == begin()') – Griddo

+0

için döngüye neden olmaz. Döngüsün ilk satırı bir azalma yapar, yani evet, sanırım. Sadece denemek için hızlı bir test yapın! Her neyse, bunun artık bu deyimi kullanmanın en güzel yolu olduğunu düşünmüyorum ve koştum bazı yeni testler artık tam optimizasyon altında yineleyicileri tersine çevirmek için belirgin bir hız artışı göstermiyor. Ancak, bu değer hala kaputun altında neler olup bittiğini not etmek ve buna göre test etmek! – mmocny

İlgili konular