2015-08-09 20 views
5

Hem C++ 11 hem de Boost'un hashmap neden yinelenen öğeleri silme sırasında yeniden boyutlandırma merak ediyorum. Bu teknik bir bellek sızıntısı olmasa bile, uygulamalarda ciddi bir sorun olabileceğini düşünüyorum (bu benim için gizli bir konuydu, geri izlemek için zor zamanlar geçirdi) ve aslında birçok uygulamayı etkileyebilirdi. Bu konteyner ile bir "tasarım hatası" mı?C++ 11/Boost `unordered_map` silme sırasında neden geri dönmez?

bunu benchmarked ve

sorunu yeniden oluşturmak için kod (VS, Clang, GCC dahil) çeşitli derleyici bültenleri etkileyen gibi görünüyor:

std::unordered_map<T1,T2> m; 

for (int i = 0; i < 5000000; i++) 
     m.insert(std::make_pair(i, new data_type)); 


for (map_type::iterator it = m.begin(); it != m.end();) { 
     delete it->second; 
     it = m.erase(it); 
} 

Ben kullandığınız bir self-contained test dosyası oluşturduk bellek kullanımını izlemek için özel ayırıcı.

Anladığım kadarıyla, bunun arkasında yatan neden yinelenen öğelerin silinmesi ve yinelenen öğelerin silinmemesi için geçerli yineleyiciler tutulmasıdır .. Öğeleri eklemek, yinelemeyi geçersiz kılan yeniden karışmalara neden olabileceğinden, bu biraz tuhaf bir gereksinimdir. Ben (Ben akıllı bir işaretçi içindeki haritayı sarılı olduğu sabit ve boşken ben sadece yeni bir boş harita yeniden nasıl

Wich olduğunu

Ama doğrudan harita yok edebilecek .., sonuçlandı Rehaş olmaktan daha hızlı olmak için nedenini bilmiyorum.). Genelde

Bildiğim kadarıyla olabildiğince

+0

Üzgünüm. Düzenleme için teşekkürler. – GameDeveloper

+6

Sanırım kendi sorunuzu doğru bir şekilde yanıtladı. Sadece mantığa katılmıyorsun. Burada, tasarım mantığını içeren teklifin bir bağlantısı vardır: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1456.html –

+1

Sadece yineleyicilerin silinmesi gereken öğeleri silerken Bunun için iyi bir gerekçe vermeden geçerliliğini yitirmiş olmalısınız (tüm okunuşta güdülen birkaç ifadeden biri gibi görünmektedir). – GameDeveloper

cevap

2

bu konuda muzdarip olabilir önbelleğe alma elemanları kapsayıcı olarak unordered_map kullanan herhangi bir uygulama (eğer önbellekten öğeleri kaldırmak isteyebilir ama genellikle kimse bir "önbellek sıfırlama" do) söyleyin ki, bu davranış, yinelemeyi geçersiz kılma gereğinin bir sonucu değildir (std::unordered_map::rehash ayrıca onları geçersiz kılmaz) std::unordered_map::erase için karmaşıklık gereksiniminin bir sonucu olduğundan, ortalamada sabit zaman almalıdır.

böyle belirtildi neden, söyleyemem, ama benim için doğru varsayılan davranış neden ben söyleyebilirim:

  1. Birçok uygulamada, içeriği benim hash tablosu zaten sıfırlamadan sonra neredeyse sabit - bu yüzden umurumda değil.
  2. Durum böyle değilse, en azından öğelerinin ortalama sayısı az ya da çok aynı kalır (büyüklük sırasına göre). Bu nedenle, zaman içinde bir çok nesne silinmiş olsa bile, kısa bir süre sonra yeni öğeleri muhtemelen eklenecektir. Bu durumda, bellek kapağını gerçekten azaltmaz ve 'un iki kez tekrarlanmasını (bir kez silindikten sonra ve yeni elemanlar ekledikten sonra) genellikle daha kompakt bir tablodan elde edebileceğim herhangi bir performans geliştirmesinden ağır basacaktır.
  3. Daha fazla sayıda öğenin silinmesi (ör., Bir filtre işleviyle), aradaki hatalar tarafından kontrol edilemediyse (max_load_factor öğelerini değiştirerek öğeleri eklerken yapabileceğiniz gibi) ciddi bir şekilde yavaşlatılır.
    Son olarak, rehabilite edilmesinin gerçekten yararlı olduğu durumlarda bile, genellikle daha iyi bir karar verebiliyorum, (örneğin, rehaş veya kopya ve takas yoluyla) std::unordere_map nolu bir genel sezgiden daha iyi bir karar verebilir.

Yine, bu noktalar onlar diğer insanların yazılım için evrensel olarak doğru olduğunu iddia ya da İlginçtir, VS2015

unordered_map ait şartname arkasında motivasyon olduğunu değil, benim tipik kullanım durumları için geçerliyse ve libstC++ * farklı rehash(0) uygulamak gibi görünüyor: tablo

  • VS2015 tablo boyutunu azaltacaktır kaydedildiği hafızayı ++ aslında küçülecek libstc

    • (yeniden tahsis) (a .k.a. kova numarası) ancak tabloyu yeniden değil. Dolayısıyla, boş bir karma haritayı yeniden doğruladıktan sonra bile, tablo için fazla bellek iade edilmeyecektir.

    Görünüşe göre, bellek izini en aza indirmenin tek taşınabilir yolu kopyalamak ve takas yapmaktır. Belgelerle ilgili olarak, bunun açıkça bir yerlerde açıkça belirtilmesi gerektiğine katılıyorum, ancak diğer yandan, örn. std::vector::erase() belgelerine uygun. Ayrıca, gereksinimleri ihlal etmeden, en azından bazen silme üzerine rehaş bir uygulama yazmak gerçekten imkansız ise,% 100 emin değilim.


    *) Aslında kaynak koduna bakarak değil, sizin ayırıcı gelen bucket_count ve getAllocatedBytes() sonuçlarından bu anlaşılmaktadır.

  • +0

    Zaman ayırdığınız için teşekkürler, Evet, varsayılan davranış olarak mükemmel bir anlam ifade ediyor, VS2015 biraz buggy gibi görünüyor? Hafızayı boşaltmanın tek yolu P_P haritasının imha edilmesidir. – GameDeveloper

    +0

    @DarioOO: Eh, daha az dinamik miyari tahsisatlarına ihtiyaç duyması avantajına sahiptir. Bu doğru seçim olsa gerek kesinlikle şüphelidir - özellikle eğer öğeleri kopyalamak pahalıysa. – MikeMB