C ++ STL Vektörler: Yineleyiciyi dizinden al?


202

Yani, bir stl vektörüne indeks [] ile elemanlara erişen bir grup kod yazdım, ama şimdi vektörün sadece bir kısmını kopyalamalıyım. Görünüşe göre vector.insert(pos, first, last)istediğim fonksiyon ... sadece ints olarak ilk ve sonuncu var. Bu değerlere yineleyici almamın güzel bir yolu var mı?



Eğer yanılmıyorsam, cevapların hiçbiri sınır kontrolü yapmaz, bu bir problem olabilir. Özellikle, std :: advance docs altta yatan kap sınırlarını aşmak için kullanırsanız davranışın tanımsız olduğunu söyler.
Martin Pecka

Yanıtlar:


295

Bunu dene:

vector<Type>::iterator nth = v.begin() + index;

4
Genellikle, STL yineleyicilerde işaretçilerle aynı aritmetiği kullanabilirsiniz. STL algoritmaları kullanırken değiştirilebilir olacak şekilde tasarlanmıştır.
Vincent Robert

18
@VincentRobert: Başka türlü. İşaretçiler, en güçlü kategori olan STL rasgele yineleyicilerinin geçerli uygulamalarıdır. Ancak ileri yineleyiciler gibi diğer daha az güçlü kategoriler aynı aritmetiği desteklemez.
MSalters

7
Ben bu cevaba benim beş sent eklemek ot istiyorum ve tavsiyestd::next(v.begin(), index)
stryku

88

@dirkgently tarafından belirtilen şekilde ( v.begin() + index )vektörler için güzel ve hızlı

ancak en genel yol ve rastgele erişim yineleyicileri için de sabit zaman çalışır. std::advance( v.begin(), index )

Kullanımdaki EDIT
farkları:

std::vector<>::iterator it = ( v.begin() + index );

veya

std::vector<>::iterator it = v.begin();
std::advance( it, index );

@litb notlarından sonra eklendi.


std :: advance ilk argüman olarak const olmayan yineleyici gerektirmez mi?
goldPseudo

std :: const ve const olmayan yineleyiciler ile ilerleyin
bayda

1
bu konuda msvc'ye güvenmemelisiniz. bu tür bir şeyi kabul etmesini sağlayan standart dışı bir uzantıya sahiptir, yine de diğer tüm derleyiciler standart davranır ve reddeder.
Johannes Schaub - litb

1
Sorun "const" anlamı üzerinde karışıklık olduğunu düşünüyorum: advance () mutlulukla T tipi bir const elemanı ifade değişebilir bir yineleyici bir const_iterator <T> üzerinde çalışacaktır; kendisi const olan bir yineleyici nesnesi üzerinde çalışmaz (yani "const iterator <T>" veya "iterator <T> const").
j_random_hacker

7
Bir ile uğraştığınızı biliyorsanız , bunu std::vectorkullanmanın bir anlamı yoktur std::advance. Sadece kapsayıcı-agnostik kod yazdığınızı düşünmeye iter (ki bunu yapmazsınız, yineleyici geçersiz kılma kurallarını, farklı çalışma zamanı karmaşıklıklarını ve ne olduğunu düşünmezsiniz). std::advanceMantıklı olduğu tek durum, ne tür bir yineleyici ile uğraştığını bilmeyen bir şablon kendiniz yazmanızdır.
Frerich Raabe

48

Ayrıca; auto it = std::next(v.begin(), index);

Güncelleme: C ++ 11x uyumlu bir derleyici gerekiyor


2
Bu C ++ 11 yolu olduğuna dikkat edilmelidir! std :: next, std :: advance ile eşdeğerdir. Aritmetik kullanmak yerine bu işlevleri kullanmak, konteyner tiplerini değiştirmeyi çok daha kolay hale getirir. Std :: begin ve std :: end gibi c-dizileri afaik üzerinde bile çalışır.
Zoomulator

2
Ayrıca şunu da belirtmek gerekir ki std :: advance, bir idiot tarafından dönüş değeri değil çıktı olarak bir referans kullandığından tasarlanmıştır.
Viktor Sehr

1
için (otomatik it = start (c); it! = end (c); advance (it, n)) {...}
Zoomulator

2
Her ikisinin de kullanımları vardır. stda :: advance, yineleyiciyi yerinde değiştirmek için kullanışlıdır. Döngülerde bir performans sorunu. Önerdiğiniz gibi, atama durumunda bir sonraki tercih ederim. Sadece aptalca olduğunu iddia etmek biraz zor buldum. Her iki işlev de temelde aynı olmalarına rağmen farklı durumlar göz önünde bulundurularak tasarlanmıştır.
Zoomulator

6
@Zoomulator: Yineleyicinizi kopyalamak bir performans sorunuysa, başa çıkmanız gereken daha büyük sorunlarınız vardır.
Mooing Duck


-3

Actutally std :: vector gerektiğinde C sekmesi olarak kullanılmak içindir. (C ++ standardı, vektör uygulaması için bildiğim kadarıyla istiyor - Wikipedia'da dizi için değiştirme ) Örneğin, bana göre bu çekim işlemini yapmak tamamen yasal:

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

Tabii ki, ya foo parametre olarak iletilen adresi kopyalamamalı ve bir yerde saklamamalıdır ya da programınızda vec'de hiçbir zaman yeni bir öğeyi itmemesini ya da kapasitesini değiştirmek istememesini sağlamalısınız. Veya risk bölümleme hatası ...

Bu nedenle, örnekleminizde

vector.insert(pos, &vec[first_index], &vec[last_index]);

Bana sadece işaretçiler olsalar neden yineleyicilere soyutlamaya karar verdiklerini merak ediyorlar ... aslında bu yetenekleri "gizliyorlar".
Mart'ta

Tutarlılık için mi? Kodunuzdaki başka herhangi bir kapsayıcı için vektör örneğini kolayca kaldırmanıza izin verdiği için.
yves Baumes

4
& vec [i], vektör <> :: yineleyici ile mutlaka uyumlu olmayan bir işaretçi verir. vec.begin () + i, örneğin, hata ayıklama modunda denetlenen yineleyiciler de dahil olmak üzere, kitaplığınızın tanımladığı yineleyici olma avantajına sahiptir. Dolayısıyla, bir işaretçiye ihtiyacınız yoksa (örneğin G / Ç için), her zaman yineleyicileri tercih etmelisiniz.
sellibitze

@KerrekSB c ++ standart taslakta 23.3.6.1'den itibaren: "Bir vektörün elemanları bitişik olarak saklanır, yani v bir vektör ise <T, Allocator>, burada T bool dışında bir türse, o zaman kimliğe & v [ n] == & v [0] + n tümü için 0 <= n <v.size () "
yves Baumes

2
@yvesBaumes: vektör yineleyicilerle ilgisi yok. Ancak, çıplak işaretçileri doğrudur vardır da yineleyiciler - onlar sadece değiliz vektör yineleyiciler.
Kerrek SB
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.