2010-03-09 7 views
6
#include <stdio.h> 
#include <stdlib.h> 
#include <memory.h> 
#include <vector> 
#include <string> 
#include <iostream> 
#include <map> 
#include <utility> 
#include <algorithm> 

void * GetMemory(size_t n) { 
    void *ptr = malloc(n); 
    printf("getMem n %d ptr 0x%x\n", n, reinterpret_cast<unsigned int> (ptr)); 
    return ptr; 
} 

void FreeMemory(void *p) { 
    free(p); 
} 

void* operator new (size_t n) { 
    void *p = GetMemory(n); 
    return p; 
} 

void* operator new [] (size_t n) { 
    void *p = GetMemory(n); 
    return p; 
} 

void operator delete (void *p) { 
    FreeMemory(p); 
} 

void operator delete [] (void *p) { 
    FreeMemory(p); 
} 

typedef std::vector<int> vec; 

int main(int argc, char *argv[]) { 
    std::map<int, vec> z; 
    vec x; 
    z.insert(std::pair<int,vec>(1,x)); 
} 

Derleme içine sokma.Bellek ayırma sırasında harita g ++ -Wall -ansi Test.cpp -o Test</p> <p>Çalışma testi ile

Neden n = 0 ile GetMemory için üç çağrı var? Boş vektör başlatma ile ilgili

cevap

8

Çubuğu bazı izleme değişken 'x' kopyalama boş setini çağırır ve bu ana değiştirin:}

int main(int argc, char *argv[]) { 
    printf("map\n"); 
    std::map<int, vec> z; 
    printf("vec\n"); 
    vec x; 
    printf("pair\n"); 
    std::pair<int,vec> y(1,x); 
    printf("insert\n"); 
    z.insert(y); 
    printf("inserted 1\n"); 
    y.first = 2; 
    printf("insert\n"); 
    z.insert(y); 
    printf("inserted 2\n"); 

Çıktı:

$ make mapinsert CXXFLAGS=-O3 -B && ./mapinsert 
g++ -O3 mapinsert.cpp -o mapinsert 
map 
vec 
pair 
getMem n 0 ptr 0x6b0258 
insert 
getMem n 0 ptr 0x6b0268 
getMem n 32 ptr 0x6b0278 
getMem n 0 ptr 0x6b02a0 
FreeMemory ptr 0x6b0268 
inserted 1 
insert 
getMem n 0 ptr 0x6b0268 
getMem n 32 ptr 0x6b02b0 
getMem n 0 ptr 0x6b02d8 
FreeMemory ptr 0x6b0268 
inserted 2 
FreeMemory ptr 0x6b0258 
FreeMemory ptr 0x6b02d8 
FreeMemory ptr 0x6b02b0 
FreeMemory ptr 0x6b02a0 
FreeMemory ptr 0x6b0278 

senin 3 0 büyüklüğünde allo Yani katyonlar:

  • Biri boş vektörü çifti içine kopyalamaktır.
  • Biri, boş vektörün bir kopyasını haritada saklamaktır.

Bu iki açıkça gereklidir. Ne hakkında emin değilim şudur:

  • Bir insert çağrısına yerde vektör kopyalamak ve bu da eklemek için çağrıda arındırılır.

(dahili olarak aramalar falan) değeriyle yerine referans olarak kendi parametre alıyor, ya da yeni harita düğümünü ayırır önce insert açıkça bir otomatik değişken içine biraz zaman bir kopyasını alıyor insert sanki. Bir hata ayıklayıcısını yakmak şu an benim için bir çaba, onu başka birine bırakacağım.

Düzenleme: gizem çözüldü. insert, std::pair<int, vec> değil, std::pair<const int, vec> alır. Boş bir vektörün fazladan kopyası, oluşturduğunuz çiftin bir (noter) geçici hale dönüştürülmesi gerektiğinden, bu geçici referansa insert aktarılır. std :: pair, hemen hemen her şeyden kurtulmanızı sağlayan bir kurgu şablonuna sahiptir./4 20.2.2:

template<class U, class V> pair(const pair<U,V> &p); 

Etkileri: gerekli olarak örtülü dönüşüm yapmak, argüman karşılık gelen üyelerinden üye başlatır.getMem çağırmaz

Ben de uygulanmasında görüyoruz, vec x; fakat vec x(0); yapar. Yani aslında:

z[1] = vec(); 

az şifre mi ve (yerine operator= çağırır rağmen) ekstra kopyasını fırsatı reddeder. En azından benim için hala 2 0 boyutlu tahsisat yapıyor.

C++ standardı, insert numaralı aramayı içeren belirli bir ifadenin sonucunu döndürmek için operator[] öğesini tanımlar. Bu, operator[]'un "sanki" make_pair ve insert etkilerinin (yani, standardın operator[] için ne olması gerektiğini belirten kadar iyi olduğu) veya yalnızca döndürülen değerin mi olduğu anlamına geldiğinden emin değilim. Belirtilen ifade ile aynı değer verir. Eğer ikincisi o zaman belki de bir uygulama bunu tek bir 0 boyutlu tahsis ile yapabilirdi. Ancak kesinlikle map, eşlenmiş türden bir çift oluşturmadan bir giriş oluşturmanın garantili bir yolu yoktur, bu nedenle 2 ayırma beklenmelidir. Veya daha doğrusu, istenen eşlenen değerin 2 kopyası: 0 büyüklüğünde bir vektörün kopyalanması 0 büyüklüğünde bir tahsisatın uygulamaya bağlı olması gerçeğidir. Eğer değer kopyalamak için gerçekten pahalı ama varsayılan-yapısı için (elementlerin dolu bir kap gibi) gerçekten ucuz bir dava olsaydı

yani, sonra aşağıdaki yararlı olabilir:

std::map<int, vec> z; 
vec x(1000); 
z[1] = x; 
// i.e. (*(z.insert(std::pair<const int, vec>(1,vec())).first)).second = x; 

ise, boyutu 4000 ve boyut 0 ile 2 arasında 2 tahsisleri yapar:

std::map<int, vec> z; 
vec x(1000); 
z.insert(std::pair<const int, vec>(2, x)); 

büyüklüğü 4000 3 yapar ve boyut 0 hiçbirinin Sonunda boyutu birinci kod ilave ayırma daha ucuz olduğu kadar büyük ikinci kodda fazladan kopyalama.

C++ 0x'deki hareket-yapıcıların bu konuda yardımcı olması muhtemel, emin değilim.

+0

Tüm çabanız için teşekkürler. Bu cevabı bir * verebilseydim, yapardım. –

+0

Bu, vektörler gibi şeyleri bir haritaya yerleştirirken en iyi uygulamanın neden yazılmamış vektör yapmak olduğunu gösteren iyi bir örnektir vec_t; typedef map map_t; vec_t dummy; map_t myvals; vec_t tvals (100000,3);/* vali */myvals.insert (map_t :: value_type (1, kukla)) first-> second.swap (tvals); Bu, sadece bir vec_t'nin harita düğümünü yapmak için kopyalanmasını ve ardından düğüm oluşturulduğunda (veya zaten var ise) değerlerin taşınmasını sağlar. Eşdeğer C++ 0x yolu myvals.insert (map_t :: value_type (1, std :: move (tvals))); –

6

Her 3 olguya:

  1. boş vektör içerecektir ağacın kök öğeyi (std :: map iç uygulanmasını) init. "Vec x" kendi başlatmanız için
  2. . std için
  3. kopya yapıcı :: 'ikinci' elemanı için çifti FreeMemory içinde
+0

Her bir haritaya eklediğinizde z, GetMemory() üçgrup olarak adlandırılır. Alttaki şu kodu eklemeyi deneyin: vec y; ; z.insert (Std :: çifti (2, y) üç daha fazla arama, n = 0 ve hatta bir boş vektör ile tüm alan 3 işaretçiler gerekir: _M_start, _M_finish ve _M_end_of_storage –

+0

@ prasoon99. : "Ve boş bir vektör bile 3 işaretçiye ihtiyaç duyar ..." - işaretçileri ve vektör örneklerini karıştırmayın! İşaretçiler bellek ayırmayı beklemez, ancak vektörün bir örneği yok Boş vektör tam olarak boş arabellek ayırır. 3 kez - benim cevabımı görebilmek için: – Dewfy

+0

gdb ile kontrol et Tüm çağrılar GetMemory() eklenti ifadeleridir. Vektör başlatma, GetMemory() için bir çağrı yapmaz. –