2013-10-17 18 views
5

, bazı geçerli yineleyici x eşit map::begin() garantilidir ++ o x böyle olduğunu başlayacak? Az önce aradığım bir fonksiyonun (fonksiyonun) bir iteratörün önüne çıkıp çıkmadığını tespit etmek istiyorum. Fonksiyon, tekrarlayıcıyı tam olarak bir pozisyon geriye doğru hareket ettirecektir.STL yineleyici ::() C++ 11 en <code>std::map</code> yılında

Yanıt, kütüphanenin geri kalanı için geçerli mi? Ben böyle bir ileri yineleyici bir şey eksiltim olan tahmin "açık kapalı yineleyici yürümek" ile

+1

Kısa yanıt: Hayır. Durumu gerçekten ele almanın başka bir yolunu bulmanız gerekiyor (ya da daha iyisi, önleyin). –

+0

@JerryCoffin bu yüzden ters yineleyicilerimiz var, cevabımı gör – TemplateRex

cevap

4

Hayır, std kapsayıcısında başlangıçtan önce yineleyiciler, hepsi UB (muhtemelen probunuzu çözmeyecek ters yineleyiciler hariç) im).

Muhtemelen söz konusu işlevi düzeltmeniz gerekiyor. Başarısız ol, onu sar ve onu aramadan önce kötü davranışı yakala. Başarısız olursa, map anahtar türü siparişine negatif bir sonsuzluk öğesi ekleyebilir ve bir sentinal değer ekleyebilirsiniz. Başarısız olursanız, map yineleyicilerinizi UB olmadan bir öncekinden başlayabilen yineleyici bağdaştırıcıları yazabilirsiniz.

Bunlar, öneri sırasına göre sırayla sipariş edilir. Her birinin başarısız olabileceği yollar var ve benim tavsiyem daha uzaklaştıkça daha fazla hataya ve tehlikeye maruz kalıyorlar.

+0

Yineleyici sarmalayıcılar * ilk bakışta temiz görünür, sonra onları nasıl kullanacağımı düşünürüm ve çok çabuk, çok çabuk alır. – thirtythreeforty

+1

@thirtythreeforty yep, bu yüzden dahil ettim, ama sadece bir uzak olarak "aman tanrım, başka hiçbir şey işe yaramaz" seçeneği. Bir destek yineleyici fascade ile sadece orta derecede kötü olur. Ya da el ile yaz. Ya da iki boost-tipi-silinen yineleyici aralıkları tembel-concatinating. (Yine, tavsiye sırasına göre). Sonuncusu sonuncusunu alırsan, hakettiğin şeyi alırsın: teoride çalışır, ama kokuyu alırsın. Kısacası, işlevi düzeltmek için, geçerli bir aralığa sahip olmadığı bir yineleyici azaltılmamalıdır. – Yakk

+2

ahem, 'std :: forward_list' bir' before_begin() 'üyesine sahip – TemplateRex

1

:

// this is better: 
for(it = mymap.rbegin(); it != mymap.rend(); ++it) { ... } 

-Jesse: Yerine

// don't do this: 
for(it = mymap.end(); --it >= mymap.begin();) { ... } 

, böyle bir ters yineleyici artırır

+0

Ters bir yineleyici kullanırsam, başka bir işlevle aynı sorunu yaşıyorum, ancak 'map' bitişi ile ve iterator * forward * 'ı taşıyarak. – thirtythreeforty

+0

Merak etme, niçin bir yineleyiciyi doğal yönünün tersine hareket ettirmek için _need_? Ne hakkında ** yapmak {...} while (it! = Mymap.begin(); ** –

+0

Ben yazıyorum haritalar bir ağaç etrafında yineleme gerekir başka bir yineleyici uygulamaktayım. 'ForwardIterator' iyi çalışıyor, şimdi Ben 'BidirectionalIterator' için gidiyorum. – thirtythreeforty

3

Standart Kitaplık kapsayıcılarının yarı açık aralıklarda [begin, end) olduğunu fark etmek çok önemlidir, yani, bir uçtan uca yineleyebilirsiniz. İki yönlü (ve rastgele) yineleyiciler için --end() da yapabilir ve eşikten geri dönebilirsiniz. *end() tarafından bir sonrakinin sonlandırılması tanımlanmamış bir davranıştır ve bu nedenle --begin() veya begin() - 1 tarafından başlatıcı yineleyici azaltılır. Buna tek bir istisna vardır: std::forward_list (before_begin()),10 (forward_list için begin() değerini azaltamayacağınızı unutmayın).

İki yönlü yineleyiciler için bu temel asimetri, ters yineleyicilerin normal yineleyiciler etrafında ince sarmalayıcılar olduğu anlamına gelir. Çoğu Standart Kitaplık uygulamasında, basitçe alt yineleme yineleyicisinin bir kopyasını base_ içerir. std::reverse_iterator değerini artırma, --base_; return *this; ve kayıttan kaldırmayı auto old = base_; return *--old; yapar. Hiçbir noktada, altta yatan yineleyici begin()'dan önce azaltılmış ve end()'un yok sayılması bu şekilde yapılmamıştır.Aşağıda

#include <iomanip> 
#include <iostream> 
#include <iterator> 
#include <map> 
#include <string> 

int main() 
{  
    auto c = std::map<int, std::string>{ {1, "hello"}, {2, "world"} }; 

    { // 1) forward iteratation 
     auto it = begin(c); 
     for (; it != end(c); ++it){} 
     std::cout << std::boolalpha << (it == c.rbegin().base()) << "\n"; 
    } 

    { // 2) meh, backward iteration 
     auto it = end(c); 
     for (; it != begin(c); --it){} 
     std::cout << std::boolalpha << (it == c.rend().base()) << "\n"; 
    } 

    { // 2') better: reverse iteration 
     auto it = c.rbegin(); 
     for (; it != c.rend(); ++it){} 
     std::cout << std::boolalpha << (it.base() == begin(c)) << "\n"; 
    } 

    { // 1') backward reverse, better avoid this 
     auto it = c.rend(); 
     for (; it != c.rbegin(); --it){} 
     std::cout << std::boolalpha << (it.base() == end(c)) << "\n"; 
    } 
} 

Live Example

(.base() altta yatan yineleyici bir geri std::reverse_iterator dönüştürür) çift yönlü ya da rastgele bir yineleyici destekleyen bir kap yineleme dört yolu ve çeşitli yineleyicileri arasındaki ilişkiler İki yönlü yinelemeyi desteklemesi gereken veri yapısına sahipseniz ancak .rbegin() veya rend() numaralı üye yineleyicileri yoksa, bunları std::reverse_iterator(end()) vearacılığıyla kolayca tanımlayabilirsiniz. Sırasıyla 10 (Standart Kitaplığın genellikle bunları uyguladığı yol).

+0

'a bakın. Cevabımın dışına çıkmak için teşekkürler, sadece cevabın UB olduğunu ve UB'nin şeytan olmadığını söylediğimi söylemek istiyorum. ** bir ** yerinde derleyin ve sorunun ne olduğunu UB olduğunu belgeleyin. Açıkça söyleniyor ki, ters yineleyicileri kullanabilmeliydi, ama ben sadece ** onun ** sorusunu cevaplıyordum. – aaronman

+3

@aaronman Azalttığın için üzüldüğünü duyduğuma üzüldüm. Adil olmak gerekirse, bunu yapmak için nedenlerimi açıklayan 3 kişiden sadece bir tanesiyim. Lütfen bunu kişisel olarak alma, cevabın saçma olduğunu söylemedim, ama SO cevapları da gelecekteki okuyuculara faydalı olmalı. UB gerçekten şeytan çünkü * sessizce * kodunuzu kırabilir. – TemplateRex

+0

Şahsen, yazdığım herhangi bir kodda UB'den kaçınacağım ama eğer birisi doğru şeyleri (ters yineleyicilerle) yapmamaya açık bir şekilde istiyse ve cevabın UB kimliği olduğunu söyleyen bir cevabı verirsem, büyük sorunun ne olduğuna bakın. Ayrıca benim cevabım üzerine yorum yapmama da saygı duyuyorum, böylece diğer DV'lerden farklı olarak size yardım edebilirim :) – aaronman