@Marc (düşündüğüm gibi) mükemmel bir analiz vermesine rağmen, bazı insanlar işleri biraz farklı bir açıdan düşünmeyi tercih edebilir.
Biri, yeniden tahsis etmenin biraz farklı bir yolunu düşünmektir. Tüm öğeleri hemen eski depolama biriminden yeni depolama birimine kopyalamak yerine, bir seferde yalnızca bir öğe kopyalamayı düşünün - yani, bir push_back işlemi yaptığınızda, yeni öğeyi yeni alana ekler ve tam olarak bir tane kopyalar. Eski uzaydan yeni uzaya eleman. 2'lik bir büyüme faktörü varsayarsak, yeni alan dolduğunda, tüm öğeleri eski alandan yeni alana kopyalamayı bitirdiğimizi ve her push_back işleminin tam olarak sabit bir zamanda gerçekleştiğini açık bir şekilde görüyoruz. Bu noktada, eski alanı atıyoruz, iki kat daha büyük kazanç sağlayan yeni bir bellek bloğu ayırıyor ve işlemi tekrarlıyorduk.
Oldukça açık bir şekilde, bunu süresiz olarak devam ettirebiliriz (veya zaten mevcut bellek olduğu sürece) ve her push_back yeni bir öğe eklemek ve eski bir öğeyi kopyalamaktan ibarettir.
Tipik bir uygulama hala tam olarak aynı sayıda kopyaya sahiptir - ancak kopyaları bir kerede bir tane yapmak yerine, mevcut öğelerin tümünü bir kerede kopyalar. Bir yandan haklısınız: Bu, push_back'in bireysel çağrılarına bakarsanız, bazılarının diğerlerinden önemli ölçüde daha yavaş olacağı anlamına gelir. Bununla birlikte, uzun vadeli bir ortalamaya bakarsak, push_back'in başlatılması başına yapılan kopyalamanın miktarı, vektörün boyutundan bağımsız olarak sabit kalır.
İşlemsel karmaşıklıkla ilgisi olmasa da, push_back başına bir öğe kopyalamak yerine neden bir şeyleri yapmanın avantajlı olduğunu belirtmeye değer olduğunu düşünüyorum, bu nedenle push_back başına süre sabit kalıyor. Dikkate alınması gereken en az üç neden var.
Birincisi sadece hafıza kullanılabilirliğidir. Eski bellek, diğer kullanımlar için sadece kopyalama bittikten sonra serbest bırakılabilir. Bir seferde yalnızca bir öğeyi kopyalarsanız, eski bellek bloğu çok daha uzun süre kalır. Aslında, esas olarak her zaman tahsis edilen bir eski bloğa ve bir yeni bloğa sahip olursunuz. İkiden küçük (genellikle istediğiniz) bir büyüme faktörüne karar verirseniz, her zaman daha fazla hafızaya ihtiyacınız olacaktır.
İkincisi, bir kerede yalnızca bir eski öğeyi kopyalarsanız, diziye dizine ekleme biraz daha zor olurdu - her dizine ekleme işleminin, verilen dizindeki öğenin o andaki eski bellek bloğunda mı, yoksa eski bellek bloğunda mı olduğunu bulması gerekir. yenisi. Bu, herhangi bir yöntemle çok karmaşık değildir, ancak bir diziye endeksleme gibi basit bir işlem için neredeyse herhangi bir yavaşlama önemli olabilir.
Üçüncüsü, hepsini bir kerede kopyalayarak, önbelleğe almanın çok daha iyi avantajlarından yararlanın. Tümünü bir kerede kopyalamak, çoğu durumda hem kaynağın hem de hedefin önbellekte kalmasını bekleyebilirsiniz; bu nedenle, bir önbellek kaçırmanın maliyeti, önbellek hattına uyacak öğelerin sayısı üzerinden itfa edilir. Bir kerede bir öğe kopyalarsanız, kopyaladığınız her öğe için kolayca bir önbelleğe sahip olabilirsiniz. Bu sadece karmaşıklığı değil sabit faktörü değiştirir, ancak yine de oldukça önemli olabilir - tipik bir makine için kolayca 10 ila 20 arasında bir faktör bekleyebilirsiniz.
Muhtemelen bir an için diğer yönü de dikkate almaya değer: gerçek zamanlı gereklilikleri olan bir sistem tasarlıyorsanız, aynı anda sadece bir elemanı aynı anda kopyalamak mantıklı gelebilir. Her ne kadar genel hız düşük olsa da (veya olmasa da), tek bir push_back işlemi için harcanan zamanla ilgili zorlu bir üst sınırınız olur - gerçek zamanlı bir tahsisatçı olduğunu düşünürsünüz (tabii ki, çoğu zaman gerçek zamanlı) Sistemler basitçe en azından gerçek zamanlı gereklilikleri olan bölümlerde belleğin dinamik olarak tahsis edilmesini yasaklar).