'For' döngüsü kullanarak C ++ Vector üzerinden yineleme


140

C ++ dilinde yeniyim. Vektörleri kullanmaya başladım ve tüm kodlarda, indeksler yoluyla bir vektör olsa da yinelemeyi gördüğümü fark ettim, fordöngünün ilk parametresi her zaman vektörü temel alan bir şeydir. Java bir ArrayList ile böyle bir şey yapabilir:

for(int i=0; i < vector.size(); i++){
   vector[i].doSomething();
}

Bunu C ++ 'da görmememin bir nedeni var mı? Kötü uygulama mu?


1
For döngüsü bir işlev değildir, bu nedenle parametreleri (veya geçtiğiniz şey olan bağımsız değişkenler) yoktur. std::vector<int>::size_type i = 0;Yine de, ya da belki gibi bir şey mi demek istiyorsun std::vector<int>::iterator it = vector.begin();?
chris

Kesinlikle, gördüğüm tüm örnekler böyle yazılıyor.
Flynn

4
Java, ben for-her döngü tercih veya yineleyiciler kullanın. Biraz farklı sözdizimi olmasına rağmen C ++ ile hemen hemen aynı.
Jesse Good


10
Buradaki cevapların çoğu Q'nun yanlış olduğunu varsayar: Tekrarlamanın en iyi / en kısa yolu std::vectornedir? , burada sorulan gerçek Q: C ++ bu görmemek için bir nedeni var mı? Kötü uygulama mu? aka Neden her zaman yineleme sırasında yineleyiciler kullanan C ++ kodu görüyorum std::vector?
Alok

Yanıtlar:


93

Bunu C ++ ile görmememin bir nedeni var mı? Kötü uygulama mu?

Hayır. Kötü bir uygulama değildir, ancak aşağıdaki yaklaşım kodunuzu belirli bir esneklik haline getirir .

Genellikle, C ++ 11 öncesi kapsayıcı öğeleri üzerinde yineleme kodu yineleyicileri kullanır, örneğin:

std::vector<int>::iterator it = vector.begin();

Bunun nedeni, kodu daha esnek hale getirmesidir.

Tüm standart kütüphane kapları yineleyicileri destekler ve sağlar. Daha sonraki bir geliştirme noktasında başka bir kapsayıcıya geçmeniz gerekiyorsa, bu kodun değiştirilmesi gerekmez.

Not: Olası her standart kütüphane kabıyla çalışan kod yazmak, göründüğü kadar kolay değildir.


25
Herkes bu özel durumda / kod snippet'inde neden yinelemelere dizinleme konusunda önerdiğinizi açıklayabilir mi? Bahsettiğiniz bu "esneklik" nedir? Şahsen, yineleyicileri sevmiyorum, kodu şişiriyorlar - aynı etki için yazmak için sadece daha fazla karakter. Özellikle kullanamazsan auto.
Violet Zürafa

8
@VioletGiraffe: Yineleyiciler kullanılırken boş aralıklar gibi belirli durumlarda yanlış gitmek zordur ve kod daha ayrıntılıdır.
Alok Kaydet

9
Neden sadece yineleyiciyi nasıl bildireceğinizi gösteriyor, ancak döngüyü yapmak için nasıl kullanmıyorsunuz ...?
underscore_d

117

Böyle bir uygulamayı görmemenizin nedeni oldukça öznel ve kesin bir cevaba sahip olamıyorum, çünkü iteratorstil kodundan ziyade bahsettiğiniz yolu kullanan kodların çoğunu gördüm .

İnsanların dikkate almama nedenleri şunlar olabilir: vector.size() döngü şeklini şunlar olabilir:

  1. Arama konusunda paranoyak olmak size()Döngü durumunda her seferinde . Ancak ya sorun değil ya da önemsiz bir şekilde düzeltilebilir
  2. tercih std::for_each() üzerinde fordöngü kendisi
  3. Daha sonra kabı std::vectordiğerinden (örneğin map, list) değiştirmek de döngü mekanizmasının değişmesini gerektirecektir, çünkü her kap desteğisize() ilmek döngüsünü

C ++ 11, konteynerler arasında hareket etmek için iyi bir olanak sağlar. Buna "döngü için aralık tabanlı" (veya Java'da "döngü için geliştirilmiş") denir.

Küçük kod ile tam geçiş yapabilirsiniz (zorunlu!) std::vector :

vector<int> vi;
...
for(int i : vi) 
  cout << "i = " << i << endl;

12
Sadece döngü için küçük bir aralık dezavantajı not etmek için : ile kullanamazsınız #pragma omp parallel for.
liborm

2
Kompakt sürümü seviyorum çünkü okunacak daha az kod var. Zihinsel ayarlamayı yaptıktan sonra anlaşılması çok daha kolaydır ve hatalar daha fazla öne çıkar. Ayrıca, standart olmayan bir yineleme olduğunda daha da açık hale gelir, çünkü çok daha büyük bir kod yığını vardır.
Code Abominator

87

Bir vektör üzerinden yineleme yapmanın en temiz yolu yineleyicilerdir:

for (auto it = begin (vector); it != end (vector); ++it) {
    it->doSomething ();
}

veya (yukarıdakine eşdeğer)

for (auto & element : vector) {
    element.doSomething ();
}

C ++ 0x öncesinde, auto öğesini yineleyici türüne göre değiştirmeniz ve genel işlevlerin başlangıcı ve bitmesi yerine üye işlevlerini kullanmanız gerekir.

Muhtemelen gördüğünüz budur. Bahsettiğiniz yaklaşımla karşılaştırıldığında, avantaj, türüne büyük ölçüde bağımlı olmamanızdır vector. vectorFarklı bir "koleksiyon türü" sınıfına geçerseniz , kodunuz yine de çalışır. Bununla birlikte, Java'da da benzer bir şey yapabilirsiniz. Kavramsal olarak fazla bir fark yoktur; Ancak C ++, bunu uygulamak için şablonlar kullanır (Java'daki jeneriklerle karşılaştırıldığında); bu nedenle yaklaşım, statik diziler gibi sınıf dışı tipler için bile beginve endişlevlerin tanımlandığı tüm türler için işe yarayacaktır . Buraya bakın: Düz diziler için aralık tabanlı nasıl çalışır?


5
otomatik, serbest başlangıç ​​/ bitiş de C ++ 11. Ayrıca, birçok durumda ++ yerine ++ kullanmalısınız.
ForEveR

Evet haklısın. Uygulama beginve endancak bir tek kılıftır.
JohnB

@JohnB birden fazla astarlıdır, çünkü sabit boyutlu diziler için de çalışır. autodiğer yandan oldukça zor olurdu.
juanchopanza

Eğer sadece vektör için ihtiyacınız varsa, bu tek astarlıdır.
JohnB

Yine de, ilk örnek yanıltıcıdır, çünkü C ++ 03'te çalışamazken, ifadeleriniz bunu öneriyor.
juanchopanza

35

Bunu yapmanın doğru yolu:

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    it->doSomething();
 }

Burada T, vektörün içindeki sınıfın türüdür. Örneğin sınıf CActivity ise, T yerine CActivity yazın.

Bu tür bir yöntem her STL üzerinde çalışacaktır (Sadece vektörler değil, biraz daha iyi).

Hala dizinleri kullanmak istiyorsanız, yol şudur:

for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
    v[i].doSomething();
}

std::vector<T>::size_typeher zaman değil size_tmi? Her zaman bunun için kullanıyorum.
Violet Zürafa

1
@VioletGiraffe Haklı olduğunuzdan eminim (gerçekten kontrol etmediniz), ancak std :: vector <T> :: size_type kullanmak daha iyi bir uygulamadır.
DiGMi

8

Yineleyicileri kullanmak için bazıları burada belirtilen birkaç güçlü neden vardır:

Kapsayıcıları daha sonra değiştirmek, kodunuzu geçersiz kılmaz.

yani, bir std :: vector'dan std :: listeye veya std :: set'e giderseniz, içerdiğiniz değere ulaşmak için sayısal indeksleri kullanamazsınız. Yineleyici kullanmak hala geçerlidir.

Geçersiz yineleme çalışma zamanı yakalanıyor

Kapsayıcınızı döngünüzün ortasında değiştirirseniz, yineleyicinizi bir sonraki kullanışınızda geçersiz bir yineleyici istisnası atar.


1
Yukarıdaki noktaları örnek kodla açıklayan bazı makalelere / yayınlara işaret edebilir misiniz? müthiş olur! veya bir tane ekleyebildiyseniz :)
Anu

5

Kimse bir tamsayı dizini ile bir dizi üzerinden yineleme yanlış dizine bir dizi abone olarak hatalı kod yazmayı kolaylaştırır bahsetti şaşırdı. Yuvalanmış kullanarak döngüler varsa, örneğin, ive jgibi indeksler, yanlış bir dizi indis olabilir jyerinei ve böylece programa bir hata ekleyebilirsiniz.

Buna karşılık, burada listelenen diğer formlar, yani aralık tabanlı fordöngü ve yineleyiciler, çok daha az hataya eğilimlidir. Dilin anlambilimi ve derleyicinin tür denetleme mekanizması, yanlışlıkla yanlış dizini kullanarak bir diziye erişmenizi önler.


4

STL ile programcılar iterators, tüm standart kaplarda uygulanan soyut bir kavram olduğundan, kapsayıcılar arasında geçiş yapmak için kullanırlar . Örneğin std::list, hiç yok operator [].


3

Otomatik operatörün kullanılması, veri türü ve vektörün boyutu veya başka herhangi bir veri yapısı hakkında endişelenmek zorunda olmadığından kullanımı gerçekten kolaylaştırır

Otomatik ve döngü için yineleme vektörü

vector<int> vec = {1,2,3,4,5}

for(auto itr : vec)
    cout << itr << " ";

Çıktı:

1 2 3 4 5

Kümeleri ve listeyi yinelemek için de bu yöntemi kullanabilirsiniz. Kullanılması oto otomatik şablonunda kullanılan veri türünü algılar ve bunu kullanmanızı sağlar. Yani, bir olsa bile vectorbir stringveya charaynı sözdizimi sadece para cezası çalışacak


1

Döngüyü yinelemenin ve değerlerini yazdırmanın doğru yolu aşağıdaki gibidir:

#include<vector>

//declare the vector of type int
vector<int> v;

//insert the 5 element in the vector
for ( unsigned int i = 0; i < 5; i++){
    v.push_back(i);
}

//print those element
for (auto it = 0; it < v.end(); i++){
    std::cout << *it << std::endl;
}

1

İşte vektörde değerleri yinelemenin ve yazdırmanın daha basit bir yolu.

for(int x: A) // for integer x in vector A
    cout<< x <<" "; 

0
 //different declaration type
    vector<int>v;  
    vector<int>v2(5,30); //size is 5 and fill up with 30
    vector<int>v3={10,20,30};
    
    //From C++11 and onwards
    for(auto itr:v2)
        cout<<"\n"<<itr;
     
     //(pre c++11)   
    for(auto itr=v3.begin(); itr !=v3.end(); itr++)
        cout<<"\n"<<*itr;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.