std :: Cd'de vektöre karşı std :: dizi


283

C ++ 'da a std::vectorve a arasındaki fark nedir std::array? Ne zaman diğerine tercih edilmeli? Her birinin artıları ve eksileri nelerdir? Ders kitabımın hepsi aynı nasıl olduklarını listelemek.


1
std::vectorİle karşılaştırması std::arrayve terimlerin nasıl farklı olduğunu arıyorum .
Zud

Zud, std::arraybir C ++ dizisi ile aynı değildir. std::arrayC ++ dizileri etrafında, işaretçiyi sınıfın kullanıcısından gizlemek gibi çok ince bir pakettir. Cevabımı güncelleyeceğim.
ClosureCowboy

Soru başlığını ve metnini açıklamanızı yansıtacak şekilde güncelledim.
Matteo Italia

Yanıtlar:


318

std::vectoröbekte depolanan, öğeler eklendiğinde veya kaldırıldığında otomatik olarak büyüyen ve daralan dinamik bir dizi 1'i içine alan bir şablon sınıfıdır . STL'nin geri kalanıyla iyi çalışmasını sağlayan tüm kancaları ( begin(), end()yineleyiciler vb.) Sağlar. Ayrıca, örneğin bir vektörün ortasına eleman eklemek gibi normal bir dizide hantal olabilecek işlemleri gerçekleştirmenize izin veren birkaç yararlı yöntem vardır (aşağıdaki öğeleri sahne arkasına taşıma işini yönetir).

Elemanları öbek üzerinde ayrılan bellekte sakladığından, statik dizilere göre biraz ek yükü vardır.

std::arraystatik olarak boyutlandırılmış bir diziyi içine alan, nesnenin kendisinde depolanan bir şablon sınıfıdır; bu, sınıfı yığına başlatırsanız dizinin kendisinin yığının üzerinde olacağı anlamına gelir. Boyutu derleme zamanında bilinmelidir (bir şablon parametresi olarak geçirilir) ve büyüyemez veya küçülemez.

Daha sınırlıdır std::vector, ancak özellikle küçük boyutlar için genellikle daha verimlidir, çünkü pratikte çoğunlukla C stili bir dizi etrafında hafif bir sargıdır. Ancak, işaretçiye örtülü dönüştürme devre dışı bırakıldığından daha güvenlidir std::vectorve diğer kapların ve diğer kapların STL ile ilgili işlevlerinin çoğunu sağlar , böylece STL algoritmaları & co ile kolayca kullanabilirsiniz. Her neyse, sabit boyutun çok sınırlı olması için çok daha az esnektir std::vector.

Bir giriş için bu makaleyestd::array bir göz atın ; üzerinde yapılabilecek işlemlere hızlı bir giriş yapmak ve belgelere bakmak isteyebilirsiniz .std::vector


  1. Aslında, standartta farklı işlemlerin maksimum karmaşıklığı olarak tanımlandığını düşünüyorum (örneğin, sabit zamanda rastgele erişim, doğrusal zamanda tüm elemanlar üzerinde yineleme, sabit amortisman zamanında öğelerin eklenmesi ve çıkarılması, vb.), ancak AFAIK'ın dinamik bir dizi kullanmak dışında bu tür gereksinimleri karşılamanın başka bir yöntemi yoktur. @Lucretiel tarafından belirtildiği gibi, standart aslında çok elemanları bitişik şekilde saklanmaktadır gerektirir öyle bir dinamik dizi nerede ilişkili ayırıcısı koyar depoladı.

6
Dipnotunuzla ilgili olarak: doğru olsa da, standart aynı zamanda dahili elemanlar üzerindeki işaretçi aritmetiğini de garanti eder, bu da bir dizi olması gerektiği anlamına gelir: & vec [9] - & vec [3] == 6 true.
Lucretiel

9
Eminim, bu vektör otomatik olarak küçülmez, ancak C ++ 11'den beri shrink_to_fit diyebilirsiniz.
Dino

Statik dizi terimi ile tamamen karıştım ve doğru terminolojinin ne olduğundan emin değilim. Statik değişken dizi değil, statik boyut dizisi (statik depolama kullanan bir dizi) anlamına gelir. stackoverflow.com/questions/2672085/… . Doğru terminoloji nedir? Statik dizi, sabit boyutlu bir dizi için özensiz bir terim mi?
Z bozonu

3
@Zboson: kesinlikle sadece sen değil, statik oldukça istismar edilmiş bir terim; staticC ++ 'daki çok anahtar kelimenin üç farklı alakasız anlamı vardır ve terim de derleme zamanında sabitlenen şeyler hakkında konuşmak için sıklıkla kullanılır. Umarım "statik boyutlu" biraz daha açıktır.
Matteo Italia

3
Dikkat edilmesi gereken bir şey: Gerçek zamanlı programlama için ( başlangıçtan sonra herhangi bir dinamik ayırma / ayırma yapmamanız gereken durumlarda ) std :: array muhtemelen std :: vector yerine tercih edilir.
TED

17

std::vector<T>Sınıfı kullanma :

  • ... yerleşik dizileri kullanmak kadar hızlıdır , yalnızca yerleşik dizilerin yapmanıza izin verdiği şeyleri yaptığınızı varsayarsak (varolan öğeleri okuyup yazabilirsiniz).

  • ... yeni elemanlar eklendiğinde otomatik olarak yeniden boyutlandırılır.

  • ... vektörün başlangıcına ya da ortasına yeni elemanlar eklemenizi sağlar , elemanların geri kalanını otomatik olarak "yukarı" kaydırır (bu mantıklı mı?). Öğelerin std::vectorgeri kalanını otomatik olarak aşağı kaydırırken, herhangi bir yerden de öğeleri kaldırmanıza izin verir .

  • ... at()yöntemle aralık kontrollü bir okuma yapmanızı sağlar ( []bu denetimin yapılmasını istemiyorsanız her zaman dizinleyicileri kullanabilirsiniz ).

Kullanılacak iki ana uyarı vardır std::vector<T>:

  1. Alttaki işaretçiye güvenilir erişiminiz yok, bu da bir dizinin adresini isteyen üçüncü taraf işlevlerle uğraşıyorsanız bir sorun olabilir .

  2. std::vector<bool>Sınıf aptalca. Bir dizi olarak değil, yoğun bir bit alanı olarak uygulanır. boolS bir dizi istiyorsanız kaçının !

  3. Kullanım sırasında, std::vector<T>s, aynı sayıda öğeye sahip bir C ++ dizisinden biraz daha büyük olacaktır. Bunun nedeni, mevcut boyutları gibi az miktarda başka bilgiyi takip etmeleri gerektiğidir ve std::vector<T>yeniden boyutlandırıldığında, ihtiyaç duyduklarından daha fazla yer ayırırlar. Bu, her yeni eleman eklendiğinde yeniden boyutlandırmalarını önlemek içindir. Bu davranış bir özel sağlayarak değiştirilebilir allocator, ancak bunu yapma gereğini hiç hissetmedim!


Düzenleme: Zud'un soruya cevabını okuduktan sonra bunu eklemeliyim:

std::array<T>Sınıf C ++ dizisi ile aynı değildir. std::array<T>C ++ dizilerinin etrafındaki çok ince bir sargıdır, birincil amacı işaretçiyi sınıfın kullanıcıdan gizlemektir (C ++ 'da, diziler örtük olarak işaretçiler olarak, genellikle dehşet verici etkiye dönüştürülür). std::array<T>Sınıf da büyüklüğü (uzunluk), çok yararlı olabilir depolar.


5
Dinamik olarak tahsis edilmiş yerleşik bir dizi kullanmak kadar 'hızlıdır.Öte yandan, otomatik bir dizi kullanmak oldukça farklı bir performansa sahip olabilir (ve yalnızca konumlandırma etkileri nedeniyle ayırma sırasında değil)
Ben Voigt

4
C ++ 11'de olmayan bool vektörler için ve sonraki sürümlerinde, arayabilecek data()bir üzerinde std::vector<T>yatan işaretçi alır. Ayrıca, 0 öğesinin adresini de alabilirsiniz (C ++ 11 ile çalışacağı garanti edilir, muhtemelen önceki sürümlerle çalışır).
Matt

16

@MatteoItalia tarafından yapılan bir noktayı vurgulamak için, verimlilik farkı verilerin saklandığı yerdir. Yığın bellek (ile gerekli vector), bellek ayırmak için sisteme çağrı yapılmasını gerektirir ve döngüleri sayıyorsanız bu pahalı olabilir. Yığın belleği (olası array) zaman açısından neredeyse "sıfır tepegöz" dür, çünkü bellek sadece yığın işaretçisini ayarlayarak ayrılır ve bir işleve girişte yalnızca bir kez yapılır. Yığın ayrıca bellek parçalanmasını önler. Emin olmak için, std::arrayher zaman yığın üzerinde olmayacak; nereye atadığınıza bağlıdır, ancak yine de vektörle karşılaştırıldığında yığından daha az bellek ayırmayı içerecektir. Eğer bir

  • küçük "dizi" (100 öğenin altında söylüyor) - (tipik bir yığın yaklaşık 8 MB'dir, bu nedenle kodunuz özyinelendiyse yığın üzerinde birkaç KB'den az veya daha az ayırmayın)
  • boyut sabit olacak
  • ömür, işlev kapsamı içindedir (veya üst sınıfla aynı kullanım ömrüne sahip bir üye değeridir)
  • döngüleri sayıyorsunuz,

kesinlikle std::arrayüzerinde bir vektör kullanın . Bu gereksinimlerden herhangi biri doğru değilse, a kullanın std::vector.


3
Güzel cevap. "Emin olmak için, std :: dizisi her zaman yığının üzerinde olmayacaktır; nereye ayırdığınıza bağlıdır" Peki çok sayıda öğeyle yığın üzerinde olmayan bir std :: dizisini nasıl oluşturabilirim?
Trilarion

4
@Trilarion new std::arraytahsis etmek için 'yeni`yi kullandığınız bir sınıfın üyesini kullanın veya bir sınıfın üyesi yapın.
Mark Lakata

Yani bu new std::arrayhala derleme zamanında boyutunu bilmek bekliyor ve boyutunu değiştiremezsiniz ama hala yığın üzerinde yaşıyor?
Trilarion

Evet. new std::arrayVs kullanmanın önemli bir avantajı yoktur new std::vector.
Mark Lakata

12

Çok boyutlu diziler kullanmayı düşünüyorsanız, std :: array ve std :: vector arasında bir ek fark vardır. Çok boyutlu bir std :: dizisi, tıpkı ac stili dizisi gibi, tüm boyutlarda bellekte paketlenmiş elemanlara sahip olacaktır. Çok boyutlu bir std :: vektör tüm boyutlarda paketlenmeyecektir.

Aşağıdaki beyanlar dikkate alındığında:

int cConc[3][5];
std::array<std::array<int, 5>, 3> aConc;
int **ptrConc;      // initialized to [3][5] via new and destructed via delete
std::vector<std::vector<int>> vConc;    // initialized to [3][5]

C stili dizideki (cConc) veya std :: dizisindeki (aConc) ilk öğeye bir işaretçi, önceki her öğeye 1 eklenerek tüm dizi boyunca yinelenebilir. Sıkıca paketlenmiştir.

Vektör dizisindeki (vConc) veya işaretçi dizisindeki (ptrConc) ilk öğeye bir işaretçi yalnızca ilk 5 (bu durumda) öğe üzerinden yinelenebilir ve daha sonra, sistem için 12 bayt (sistemimde) ek yükü vardır. sonraki vektör.

Bu, [3] [1000] dizisi olarak başlatılan bir std :: vector> dizisinin bellekte [1000] [3] dizisi olarak başlatılan dizinden çok daha küçük olacağı ve her ikisinin de bellekte bir std'den daha büyük olacağı anlamına gelir: Dizi her iki şekilde de tahsis edilir.

Bu ayrıca, bellek yükünü hesaba katmadan openGL'ye çok boyutlu bir vektör (veya işaretçi) dizisini geçemeyeceğiniz anlamına gelir, ancak çok boyutlu bir std :: dizisini openGL'ye geçirebilir ve çalışmasını sağlayabilirsiniz.


-17

Bir dizi ayrılan bir bellek iken, vektör bir kapsayıcı sınıftır.


23
Cevabınız std::vector<T>karşısındakine değiniyor gibi gözüküyor T[], ancak soru std::vector<T>karşıttır std::array<T>.
Keith Pinson
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.