C ++ 'da diziler veya std :: vektörleri kullanarak, performans farkı nedir?


208

C ++ kursumuzda artık C ++ dizilerini yeni projelerde kullanmamanızı öneriyorlar. Bildiğim kadarıyla Stroustroup'un kendisi dizileri kullanmamayı önermektedir. Ancak önemli performans farklılıkları var mı?


2
Neden bir performans açığı olduğunu düşünüyorsunuz?
Martin York

99
Çünkü genellikle daha iyi işlevsellik ile en kötü performans gelir.
tunnuz

19
Erken optimizasyon konusunda hemfikirim, ancak ön tarafta daha iyi depolama yönteminin seçilmesi çok mantıklı. Genellikle gerçek dünyada kodun gönderilmesi gerekir ve bir sonraki ürün geliştirilir ve optimizasyon adımı asla gerçekleşmez.
Karınca

132
Keşke insanlar "erken optimizasyon!" Birisi performansla ilgili basit bir soru sorduğunda! soruyu cevaplayın ve sadece PREMATELY olarak insanların erken bir şey yaptığını varsaymayın.
d7samurai

4
@ d7samaurai: katılıyorum, henüz kimsenin kullanmayı denediğini görmedimint main(int argc, const std::vector<string>& argv)
Mark K Cowan

Yanıtlar:


189

C ++ dizileri ile new(yani dinamik diziler kullanarak) kullanmaktan kaçınılmalıdır. Boyutu takip etmeniz gereken bir sorun var ve bunları manuel olarak silmeniz ve her türlü temizlik işlemini yapmanız gerekiyor.

Aralık denetiminiz olmadığından yığın üzerinde dizilerin kullanılması da önerilmez; diziyi iletmek boyutu (dizi - işaretçi dönüşümü) hakkında herhangi bir bilgiyi kaybeder. Bu boost::arraydurumda, bir C ++ dizisini küçük bir sınıfa saran sizeve üzerinde yineleme yapmak için bir işlev ve yineleyiciler sağlayan kullanmalısınız.

Şimdi std :: vector vs yerli C ++ dizileri (internetten alınmıştır):

// Comparison of assembly code generated for basic indexing, dereferencing, 
// and increment operations on vectors and arrays/pointers.

// Assembly code was generated by gcc 4.1.0 invoked with  g++ -O3 -S  on a 
// x86_64-suse-linux machine.

#include <vector>

struct S
{
  int padding;

  std::vector<int> v;
  int * p;
  std::vector<int>::iterator i;
};

int pointer_index (S & s) { return s.p[3]; }
  // movq    32(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

int vector_index (S & s) { return s.v[3]; }
  // movq    8(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

// Conclusion: Indexing a vector is the same damn thing as indexing a pointer.

int pointer_deref (S & s) { return *s.p; }
  // movq    32(%rdi), %rax
  // movl    (%rax), %eax
  // ret

int iterator_deref (S & s) { return *s.i; }
  // movq    40(%rdi), %rax
  // movl    (%rax), %eax
  // ret

// Conclusion: Dereferencing a vector iterator is the same damn thing 
// as dereferencing a pointer.

void pointer_increment (S & s) { ++s.p; }
  // addq    $4, 32(%rdi)
  // ret

void iterator_increment (S & s) { ++s.i; }
  // addq    $4, 40(%rdi)
  // ret

// Conclusion: Incrementing a vector iterator is the same damn thing as 
// incrementing a pointer.

Not: ile diziler tahsis ederse newolmayan sınıf nesneleri (düz gibi tahsis intkullanıcı tanımlı yapıcı olmayan) ya da sınıfları ve size elemanları kullanılarak, başlangıçta başlatıldı olmasını istemiyoruz newçünkü performans avantajları olabilir -allocated diziler std::vectorbaşlatılırken tüm unsurları için varsayılan değerler (örneğin int için 0) (bana hatırlatmak için @bernie'ye kredi).


77
Kim lanet olası AT&T sözdizimini icat etti? Sadece bilseydim ... :)
Mehrdad Afshari

4
Bu Visual C ++ derleyicisi için geçerli değildir. Ama GCC için öyle.
toto

5
Cevabım nokta, vektör gelmez ise sahip işaretçi işlemlerini Tekabül daha yavaş olması. Tabii ki, (hata ayıklama modunu da etkinleştirerek elde etmek kolay olabilir ) :)
Johannes Schaub - litb

18
+1 "Bir vektörü endekslemek bir işaretçiyi indekslemekle aynı şeydir." ve diğer sonuçlar için de.
Nawaz

3
@ Piotr99 Sizinle tartışmayacağım, ancak daha üst düzey dilleri öğrendikten sonra montajı öğrendiğinizde Intel sözdizimi, geriye, önekli (sayılar), son ekli (talimatlar) ve belirsiz (belleğe erişme) ) AT&T sözdiziminin doğası.
Cole Johnson

73

Mikro optimize edici insanlar için giriş

Hatırlamak:

"Programcılar, programlarının kritik olmayan bölümlerinin hızını düşünmek veya bunlardan endişe etmek için çok fazla zaman harcıyorlar ve bu verimlilik girişimlerinin hata ayıklama ve bakım dikkate alındığında gerçekten güçlü bir olumsuz etkisi var. Zamanın% 97'si: erken optimizasyon tüm kötülüğün köküdür, ancak fırsatlarımızı bu kritik% 3'te geçmemeliyiz "dedi.

( Tam teklif için metamorfoza teşekkürler )

Sadece daha düşük seviyeli olması gerektiğinden daha hızlı olduğuna inandığınız için bir vektör (veya herhangi bir şey) yerine C dizisi kullanmayın. Yanlış olur.

Varsayılan vektör (veya ihtiyacınıza göre uyarlanmış güvenli kap) ile kullanın ve daha sonra profil oluşturucunuz bir sorun olduğunu söylüyorsa, daha iyi bir algoritma kullanarak veya kap değiştirerek onu optimize edip edemeyeceğinize bakın.

Bu, orijinal soruya geri dönebileceğimizi söyledi.

Statik / Dinamik Dizi?

C ++ dizi sınıfları düşük seviyeli C dizisinden daha iyi davranırlar çünkü kendileri hakkında çok şey bilirler ve C dizilerinin yapamayacağı soruları cevaplayabilirler. Kendilerini temizleyebilirler. Ve daha da önemlisi, genellikle şablonlar ve / veya satır içi satırlar kullanılarak yazılır, yani hata ayıklamada çok sayıda koda görünen, sürüm oluşturmada üretilen kodun çok az veya hiç olmadığı anlamına gelir, yani yerleşik daha az güvenli rekabetleriyle hiçbir fark yoktur.

Sonuçta, iki kategoriye ayrılır:

Dinamik diziler

Malloc-ed / new-ed dizisine bir işaretçi kullanmak en iyi std :: vector sürümü kadar hızlı ve çok daha az güvenli olacaktır ( litb'nin gönderisine bakın ).

Bu yüzden bir std :: vector kullanın.

Statik diziler

Statik bir dizi kullanmak en iyisi olacaktır:

  • std :: dizi sürümü kadar hızlı
  • ve çok daha az güvenli.

Bu yüzden bir std :: dizisi kullanın .

Başlatılmamış bellek

Bazen bir kullanma vectornedeniyle yerine bir ham tampon görünür bir maliyet doğurur vectorinşaatında tamponunu ilk olacak kod cümledeki ise etmedikleri söylediği gibi, bernie onun içinde tarafından cevap .

Bu durumda, bir unique_ptryerine vectorveya kullanarak kod durumunuzda istisnai değilse, aslında buffer_ownerbu belleğe sahip olacak bir sınıf yazın ve buna dahil olmak üzere kolay ve güvenli erişim sağlayın. yeniden boyutlandırma ( realloc? kullanarak ) veya ihtiyacınız olan bonuslar .


1
Statik dizileri ele aldığınız için teşekkür ederiz - performans nedenleriyle dinamik olarak bellek ayırmanıza izin verilmiyorsa - std :: vector işe yaramaz.
Tom

10
"Statik bir dizi kullanmak en iyi boost :: array sürümü kadar hızlı olacaktır" dediğinizde, ne kadar taraflı olduğunuzu gösterir. Etrafında diğeri olmalı, Boost: dizi en iyi statik diziler gibi hızlı olabilir.
toto

3
@toto: Bu bir yanlış anlamadır: "Statik bir dizi kullanmak en iyi ((boost :: dizi sürümü kadar hızlı) && (çok daha az güvenli))" şeklinde okumalısınız. Bunu açıklığa kavuşturmak için yayını düzenleyeceğim. Bu arada, şüphenin yararı için teşekkür ederim.
paercebal

1
std :: array ne olacak?
paulm

4
Her zaman teklifin tamamını göster. "Programcılar, programlarının kritik olmayan bölümlerinin hızını düşünmek veya bunlardan endişe etmek için çok fazla zaman harcıyorlar ve bu verimlilik girişimlerinin hata ayıklama ve bakım dikkate alındığında gerçekten güçlü bir olumsuz etkisi var. Zamanın% 97'si: erken optimizasyon tüm kötülüklerin köküdür. Yine de bu kritik% 3'teki fırsatlarımızı kaçırmamalıyız. " Aksi takdirde anlamsız bir ses ısırığı haline gelir.
başkalaşım

32

Vektörler kaputun altındaki dizilerdir. Performans aynı.

Bir performans sorunuyla karşılaşabileceğiniz bir yer, vektörü başlamak için doğru şekilde boyutlandırmamaktır.

Bir vektör dolduğunda, kendisini yeniden boyutlandıracak ve bu da yeni bir dizi tahsisi, ardından n kopya yapıcısı, ardından yaklaşık n yıkıcı çağrısı ve ardından bir dizi silme anlamına gelebilir.

Yapınız / yıkımınız pahalıysa, vektörü başlamak için doğru boyutta yapmaktan daha iyidir.

Bunu göstermenin basit bir yolu var. Ne zaman inşa edildiğini / yok edildiğini / kopyalandığını / atandığını gösteren basit bir sınıf oluşturun. Bunlardan bir vektör oluşturun ve bunları vektörün arka ucuna itmeye başlayın. Vektör dolduğunda, vektör yeniden boyutlandıkça bir aktivite grubu olacaktır. Ardından, beklenen öğe sayısına göre boyutlandırılmış vektör ile tekrar deneyin. Farkı göreceksin.


4
Avlanma: performans aynı büyük O. std :: vector'a sahiptir ve muhtemelen biraz zamana mal olan biraz defter tutma yapar. OTOH, kendi dinamik dizilerinizi döndürürken aynı defter tutma işleminin çoğunu yaparsınız.
dmckee --- ex-moderator kitten

Evet anladım. Onun sorunun itme olsa da, performans farklılıkları neydi ..... Bunu ele almaya çalıştım.
EvilTeach

Gcc'nin std :: vector'u, push_back'i çağırırsanız kapasiteyi tek tek arttırır.
bjhend

3
@bjhend O zaman gcc'nin std::vectorsesleri standartlara uygun değil mi? Ben standart vector::push_backsabit amortisman sahip gerektirir gerektirir ve push_backreallocs hesaba sonra her biri için kapasite 1 ^ n karmaşıklık olacağını düşünüyorum. - Üstel kapasite üzerinde artış çeşit varsayarsak push_backve insert, bir başarısızlık reservevektör içerik nüsha olarak en fazla sabit faktör artışa yol açacaktır. 1.5 üstel vektör büyüme faktörü, başarısız olursanız ~ 3x kopya anlamına gelir reserve().
Yakk - Adam Nevraumont

3
@ yanılıyorsun. Standart üstel büyümeyi yasaklar: § 23.2.3 paragraf 16, “Tablo 101, bazı dizi kapsayıcıları için sağlanan işlemleri, ancak diğerleri için sağlanan işlemleri listelemektedir. bunları itfa edilmiş sabit zaman alacak şekilde uygular. " (tablo 101, içinde push_back olan tablodur). Şimdi lütfen FUD yaymayı bırakın. Hiçbir genel uygulama bu gereksinimi ihlal etmez. Microsoft'un standart C ++ kütüphanesi 1.5x faktörüyle, GCC ise 2x faktörüyle büyüyor.
R. Martinho Fernandes

27

Şeye yanıt verdiklerini Mehrdad söyledi:

Ancak, hala dizilere ihtiyaç duyduğunuz durumlar olabilir. Düşük seviye koduyla (yani montaj) veya diziler gerektiren eski kütüphanelerle arayüz oluştururken, vektörleri kullanamayabilirsiniz.

Hiç doğru değil. Vektörler, kullanırsanız dizilere / işaretçilere güzel bir şekilde düşer:

vector<double> vector;
vector.push_back(42);

double *array = &(*vector.begin());

// pass the array to whatever low-level code you have

Bu, tüm önemli STL uygulamaları için geçerlidir. Bir sonraki standartta, (bugün iyi olsa da) çalışması gerekecek.


1
Mevcut standart böyle bir şey söylemiyor. Bu ima edilir ve sürekli depolama olarak uygulanır. Ancak standart sadece rastgele bir erişim kabı (yineleyiciler kullanarak) olduğunu söylüyor. Bir sonraki standart açık olacaktır.
Frank Krueger

1
& * v.begin () yalnızca & operatörünü yineleyicinin referansının kaldırılması sonucuna uygular. Referans gösterme HERHANGİ BİR tür döndürebilir. Adres-operatörünün kullanılması ile HERHANGİ BİR tür tekrar dönebilir. Standart bunu bitişik bir bellek alanına işaretçi olarak tanımlamaz.
Frank Krueger

15
Standardın orijinal 1998 metni gerçekten gerektirmedi, ancak 2003'te buna değinen bir zeyilname vardı, bu yüzden gerçekten Standart tarafından kapsanıyor. otlarutter.wordpress.com/2008/04/07/…
Nemanja Trifunovic

2
C ++ 03 , boyut aralığı dahilinde &v[n] == &v[0] + nsağlanan geçerli olduğunu açıkça söylüyor n. Bu ifadeyi içeren paragraf C ++ 11 ile değişmedi.
bjhend

2
neden sadece std :: vector :: data () kullanmıyorsunuz?
paulm

15

C ++ 11'de düz dizileri kullanmak için daha az nedeniniz var.

Doğada sahip oldukları özelliklere bağlı olarak doğada en hızlıdan en yavaşa 3 çeşit dizi vardır (elbette uygulama kalitesi, listede 3. durum için bile işleri gerçekten hızlı hale getirebilir):

  1. Derleme zamanında bilinen boyutta statik. ---std::array<T, N>
  2. Çalışma zamanında bilinen ve asla yeniden boyutlandırılmamış boyutta dinamik. Buradaki tipik optimizasyon, dizi doğrudan yığına tahsis edilebilirse. - Veri yok . Belki dynarrayC ++ 14'ten sonra C ++ TS'de. C'de VLA'lar vardır
  3. Dinamik ve çalışma zamanında yeniden boyutlandırılabilir. ---std::vector<T>

İçin 1. sabit parçaların sayısı kullanımı ile düz statik diziler std::array<T, N>C ++ 11.

Çalışma zamanında belirtilen 2. sabit boyutlu diziler için, ancak boyutlarını değiştirmez, C ++ 14'te tartışma var, ancak teknik bir spesifikasyona taşındı ve sonunda C ++ 14'ten yapıldı.

İçin 3. std::vector<T> genellikle yığın bellek için soracaktır . Bu std::vector<T, MyAlloc<T>>durumun performans sonuçları olabilir, ancak durumu özel bir ayırıcıyla iyileştirmek için kullanabilirsiniz . Buna kıyasla avantajı T mytype[] = new MyType[n];, yeniden boyutlandırabilmeniz ve düz dizilerin yaptığı gibi bir işaretçiye bozulmayacağıdır.

İşaretçilere çürümeyen dizileri önlemek için belirtilen standart kitaplık türlerini kullanın . Zamandan ayıklama kazandıracak ve performansı tam olarak sen de aynı özelliklere kullanırsanız basit dizilerin ile aynı.


2
st36 :: dynarray. n3690'a yapılan ulusal vücut yorumlarını inceledikten sonra, bu kütüphane bileşeni C ++ 14 çalışma belgesinden ayrı bir Teknik Şartnamede seçilmiştir. Bu kap, n3797 itibariyle C ++ 14 taslağının bir parçası değildir. dan en.cppreference.com/w/cpp/container/dynarray
Muhammed El-Nakib

1
çok iyi bir cevap. kısa ve özetleme, yine de her şeyden daha fazla ayrıntı.
Mohamed El-Nakib

6

STL ile git. Performans cezası yoktur. Algoritmalar çok verimlidir ve çoğumuzun düşünmeyeceği ayrıntıları ele almakta iyi bir iş çıkarırlar.


5

STL yoğun şekilde optimize edilmiş bir kütüphanedir. Aslında, yüksek performansın gerekli olabileceği oyunlarda STL kullanılması bile önerilmektedir. Diziler günlük görevlerde kullanılmak için fazla hataya açıktır. Bugünün derleyicileri de çok akıllı ve gerçekten STL ile mükemmel kod üretebilir. Ne yaptığınızı biliyorsanız, STL genellikle gerekli performansı sağlayabilir. Örneğin, vektörleri gerekli boyuta başlatarak (başlangıçtan biliyorsanız, temel olarak dizi performansına erişebilirsiniz). Ancak, hala dizilere ihtiyaç duyduğunuz durumlar olabilir. Düşük seviye koduyla (yani montaj) veya diziler gerektiren eski kütüphanelerle arayüz oluştururken, vektörleri kullanamayabilirsiniz.


4
vektörün bitişik olduğu göz önüne alındığında, diziler gerektiren kütüphanelerle arayüz kurmak hala oldukça kolaydır.
Greg Rogers

Evet, ancak vektörün iç öğelerini karıştırmak istiyorsanız, bir vektör kullanmanın daha az avantajı olacaktır. Bu arada, anahtar kelime "olmayabilir".
Mehrdad Afshari

3
Vektörlerin nerede kullanılamayacağını bildiğim tek bir durum var: eğer boyut 0 ise & a [0] veya & * a.begin () çalışmaz. c ++ 1x, elemanları saklayan dahili arabelleği döndüren a.data () işlevini tanıtarak bunu düzeltir
Johannes Schaub - litb

Bunu yazarken kafamdaki belirli senaryo, yığın tabanlı dizilerdi.
Mehrdad Afshari

1
Arabirim vektörü veya C ile herhangi bir bitişik kap: vec.data()veri ve vec.size()boyut için. İşte bu kadar kolay.
Germán Diago

5

Duli'nin katkısı hakkında .

Sonuç, tamsayı dizilerinin tamsayıların vektörlerinden daha hızlı olmasıdır (benim örneğimde 5 kez). Ancak, daha karmaşık / hizalanmamış veriler için diziler ve vektörler aynı hızdadır.


3

Yazılımı hata ayıklama modunda derlerseniz, birçok derleyici vektörün erişimci işlevlerini satır içi yapmaz. Bu, performansın önemli olduğu durumlarda stl vektör uygulamasını çok daha yavaş hale getirecektir. Ayrıca, hata ayıklayıcıda ne kadar bellek ayrıldığını görebileceğiniz için kodun hata ayıklamasını kolaylaştırır.

Optimize edilmiş modda, stl vektörünün bir dizinin verimliliğine yaklaşmasını beklerim. Bunun nedeni, vektör yöntemlerinin birçoğunun şimdi satır içi olması.


Bunu belirtmek önemlidir. Hata ayıklama STL öğelerinin profilini çıkarmak çok, çok yavaştır. İnsanların STL şeylerinin yavaş olmasının nedenlerinden biri de budur.
Erik Aronesty

3

Başlatılmamış bir arabellek (örneğin, hedef olarak kullanmak için ) std::vectoristediğinizde bir vs ham dizisini kullanmanın kesinlikle bir performans etkisi vardır . Bir varsayılan kurucuyu kullanarak tüm öğelerini başlatır. Ham bir dizi olmayacak.memcpy()std::vector

Bağımsız değişken alan yapıcı için c ++ özelliği (bu üçüncü formdur) şunu belirtir:std:vectorcount

`İsteğe bağlı olarak kullanıcı tarafından sağlanan bir ayırıcı tahsisi kullanarak çeşitli veri kaynaklarından yeni bir kap oluşturur.

3) Kapsayıcıyı varsayılan olarak eklenen T sayısı ile oluşturur. Kopya yapılmaz.

karmaşa

2-3) Sayısal olarak doğrusal

Ham bir dizi bu başlatma maliyetine dahil değildir.

Ayrıca bkz. Tüm öğelerini başlatmak için std :: vector <> 'dan nasıl kaçınabilirim?


2

İkisi arasındaki performans farkı çok fazla uygulamaya bağımlıdır - kötü uygulanmış bir std :: vector'u optimum bir dizi uygulamasına karşılaştırırsanız, dizi kazanır, ancak tersine çevirir ve vektör kazanır ...

Elmaları elma ile karşılaştırdığınız sürece (hem dizi hem de vektör sabit sayıda öğeye sahiptir veya her ikisi de dinamik olarak yeniden boyutlandırılır) STL kodlama uygulamasını aldığınız sürece performans farkının ihmal edilebilir olduğunu düşünürdüm. Standart C ++ kapsayıcılarını kullanmanın, standart C ++ kitaplığının bir parçası olan önceden haddelenmiş algoritmaları kullanmanıza izin verdiğini ve çoğunun, kendiniz oluşturduğunuz aynı algoritmanın ortalama uygulamasından daha iyi performans gösterebileceğini unutmayın. .

Bununla birlikte, IMHO vektörü, hata ayıklama STL'si ile bir hata ayıklama senaryosunda kazanır, çünkü uygun bir hata ayıklama moduna sahip çoğu STL uygulaması, en azından standart kaplarla çalışırken yapılan tipik hataları vurgulayabilir / katlayabilir.

Oh, ve unutmayın ki dizi ve vektör aynı bellek düzenini paylaşır, böylece verileri temel dizileri bekleyen eski C veya C ++ koduna aktarmak için vektörleri kullanabilirsiniz. Yine de, bu senaryoda bahislerin çoğunun kapalı olduğunu ve ham bellekle tekrar uğraştığınızı unutmayın.


1
Performans gereksinimlerini (O (1) aramalar ve eklemeler) karşılamak için neredeyse dinamik diziler kullanarak std :: vector <> uygulamak zorunda olduğunuzu düşünüyorum . Tabii ki bunu yapmanın bariz yolu budur.
dmckee --- ex-moderator kitten

Sadece performans gereksinimleri değil, aynı zamanda depolama alanının bitişik olması gerekliliği. Kötü bir vektör uygulaması, dizi ile API arasında çok fazla dolaylı katman oluşturacaktır. İyi bir vektör uygulaması, satır içi kod, döngülerde kullanılan SIMD vb. İçin izin verir.
Max Lybbert

Açıklandığı gibi kötü bir vektör uygulaması standarda uygun olmaz. Dolaylı istiyorsanız, std::dequekullanılabilir.
Phil1970

1

Boyutu dinamik olarak ayarlamanız gerekmiyorsa, kapasiteyi kaydetmek için bellek ek yükünüz vardır (bir işaretçi / size_t). Bu kadar.


1

Bir satır içi işlev içinde bir satır içi işlev içinde vektör erişimine sahip olduğunuz, derleyicinin satır içinde ne yapacağının ötesine geçtiğiniz ve bir işlev çağrısını zorlayacağı bazı kenar durumlar olabilir. Bu endişelenmeye değmeyecek kadar nadir olurdu - genel olarak litb ile aynı fikirde olurdum .

Henüz kimsenin bundan bahsetmediğine şaşırdım - bir sorun olduğu kanıtlanana kadar performans konusunda endişelenmeyin, sonra kıyaslama yapın.


1

Temel kaygının performans değil güvenlik olduğunu savunuyorum. Bir vektörün size çok fazla acı kazandıracağı dizilerle (örneğin yeniden boyutlandırmayı düşünün) birçok hata yapabilirsiniz.


1

Vektörler, dizinin boyutunu içerdikleri için dizilerden biraz daha fazla bellek kullanır. Ayrıca programların sabit disk boyutunu ve muhtemelen programların bellek alanını artırırlar. Bu artışlar küçüktür, ancak gömülü bir sistemle çalışıyorsanız önemli olabilir. Bu farklılıkların önemli olduğu birçok yer olsa da C ++ yerine C'yi kullanacağınız yerlerdir.


2
Bu önemliyse, dinamik olarak boyutlu diziler kullanmıyorsunuzdur ve bu nedenle dizilerinizin boyutunu değiştirmesine gerek yoktur. (Öyle olsaydı, boyutu bir şekilde depolarsınız). Bu nedenle, yanılmıyorsam boost :: array de kullanabilirsiniz - ve bunun bir yerde "boyutu saklamak" gerektiğini söyleyen nedir?
Arafangion

1

Aşağıdaki basit test:

C ++ Dizi vs Vektör performans testi açıklaması

"Vektörler ve diziler / işaretçiler üzerindeki temel indeksleme, kayıt silme ve arttırma işlemleri için oluşturulan montaj kodunun karşılaştırılması" ile çelişmektedir.

Diziler ve vektörler arasında bir fark olmalıdır. Test diyor ki ... sadece dene, kod orada ...


1

Bazen diziler gerçekten vektörlerden daha iyidir. Her zaman sabit uzunlukta bir nesne kümesini manipüle ediyorsanız, diziler daha iyidir. Aşağıdaki kod snippet'lerini göz önünde bulundurun:

int main() {
int v[3];
v[0]=1; v[1]=2;v[2]=3;
int sum;
int starttime=time(NULL);
cout << starttime << endl;
for (int i=0;i<50000;i++)
for (int j=0;j<10000;j++) {
X x(v);
sum+=x.first();
}
int endtime=time(NULL);
cout << endtime << endl;
cout << endtime - starttime << endl;

}

burada X'in vektör versiyonu

class X {
vector<int> vec;
public:
X(const vector<int>& v) {vec = v;}
int first() { return vec[0];}
};

ve X'in dizi sürümü:

class X {
int f[3];

public:
X(int a[]) {f[0]=a[0]; f[1]=a[1];f[2]=a[2];}
int first() { return f[0];}
};

Main () dizisi sürümü daha hızlı olacaktır, çünkü iç döngüde her seferinde "yeni" yükünü engelliyoruz.

(Bu kod benim tarafımdan comp.lang.c ++ 'a gönderildi).


1

Çok boyutlu davranışı temsil etmek için vektörler kullanıyorsanız, bir performans isabeti vardır.

2d + vektörler performansa neden olur mu?

Burada önemli olan, her bir alt vektörün boyut bilgisine sahip küçük bir ek yükü olmasıdır ve verilerin seri hale getirilmesi gerekmeyecektir (çok boyutlu c dizilerinde olduğu gibi). Bu serileştirme eksikliği mikro optimizasyon fırsatlarından daha fazlasını sunabilir. Çok boyutlu diziler yapıyorsanız, std :: vector'u genişletmek ve kendi get / set / resize bit işlevinizi yuvarlamak en iyisi olabilir.


0

Sabit uzunluklu bir dizi (örneğin , 1000'de sabit tutulma boyutuyla int* v = new int[1000];vs) varsayarsak , gerçekten önemli olan (veya en azından benzer bir ikilemde olduğumda benim için önemli olan) tek performans değerlendirmesi, öğesi. STL'nin vektör koduna baktım ve işte bulduğum şey:std::vector<int> v(1000);v

const_reference
operator[](size_type __n) const
{ return *(this->_M_impl._M_start + __n); }

Bu işlev kesinlikle derleyici tarafından çizilecektir. Yani, yapmayı planladığınız tek şey v, öğelerine erişmek olduğu operator[]sürece, performansta gerçekten herhangi bir fark olmaması gerektiği gibi görünüyor.

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.