2014-06-26 30 views
18

Son zamanlarda ISO C++ standardı yeniden okuma ve çok ilginç bir not bulundu: std::vector için, std::vector<T> türüne T tek kısıt kopya kurucu olması gerektiğini tip T olduğunustd :: vektör eki nasıl uygulanır? C++

Not. Aslında, ekleme sırasında vektörün belleği doluysa, size = 2 * oldSize'un yeni bir belleğini ayırır (bu, uygulamaya bağlıdır) ve daha sonra eski öğeleri kopyalayıp o öğeyi ekler.

Ama Bekle ?? tip T bir varsayılan kurucu olmayabilir çünkü

, ptr = new T[2*size];

  1. Bu yapıldığında nasıl böyle bir şeye ihtiyacım türde yeni bellek ayırmak için?
  2. Öyleyse Atama, belleği ayırdıktan sonra eski değerleri yeni belleğe atamalıyız, değil mi?
  3. Bu 2 şeyi göz önünde bulundurmak için, std::vector bunu "YALNIZCA KOPYA YAPISI" ile nasıl yapıyor? Hangi uygulama ve dil deyimleri kullanılır?
+4

* * * dizi-'new' ile bitti. Array-'new', sadece keşfettiğiniz gibi, dilin tam bir yanlışlığı ve tamamen işe yaramaz. Bunun yerine, bellek ayırma ve nesne oluşturma birbirinden tamamen ayrı yapılır. –

+0

Açık varsayılan derleyici sağlanmamışsa derleyici bir tane oluşturacaktır. – littleadv

+2

@littleadv sınıfının herhangi bir türden kullanıcı tanımlı bir kurucusu varsa, o zaman derleyici tarafından üretilen varsayılan kurucu yok –

cevap

4

Genel kural olarak, standart kapsayıcılar, numaralı ayırmayı ayırmadan ayırırlar (siz de yazdığınız kaplarda olduğu gibi). standart konteyner varsayılan durumda ayırma ve başlatma ancak her ikisinin özelleştirilmesine izin için çok karmaşık bir mekanizma kullanarak, bu için yerleşim yeni bellek tahsis operator new/operator deletefonksiyonları kullanılarak kaynar onu başlatmak ve nesneleri yok etmek için yıkıcı için açık bir çağrı.Diğer bir deyişle, arasında insteaad sekansı

p = new T[n]; 
// ... 
delete [] p; 

kullandığı.

p = operator new(n * sizeof(T)); 
for (int i = 0; i != n; ++ i) { 
    new (p + i) T(otherValue); 
} 

// ... 
for (int i = 0; i != n; ++ i) { 
    p->~T(); 
} 
operator delete(p); 

(bu daha karmaşık olacak, radikal basitleştirmedir temel kavram göstermek için Uygulamada , istisna güvenlik nedenlerinden dolayı, örneğin.)

1

emplace_back düşünün(): büyük ihtimalle vektör unititialized belleğin yeni yığını ayırır, sonra yerinde nesneleri kopyalayıp inşa etmek, yeni bir yerleşim çalışır.

26

O ayırıcı kullanarak kopya ile bir öğe oluşturmak için (yineleyici, val) inşa ayırıcı ham bellek ve aşağıdaki çağrıyı almak için) ( tahsis işlev çağrısı ile yapılır yerleşim yeni, yani buna benzer bir şey:

/* approach similar to std::uninitialized fill taken */ 
template<typename T, typename A > 
vector<T,A>::vector(size_type n, const T& val, const A& a) : alloc(a) // copy the allocator 
{ 
    /* keep track of which elements have been constructed 
    * and destroy those and only those in case of exception */ 
    v = alloc.allocate(n); // get memory for elements 
    iterator p;    // declared before try{} so it is still valid in catch{} block 

    try { 
     iterator end = v + n; 
     for(p = v; p != end; ++p) 
      alloc.construct(p, val); /* construct elements (placement new): 
             e g. void construct(pointer p, const T& val) 
             { ::new((void *)p) T(val); } */ 
     last = space = p; 
    } catch(...) { 
     for(iterator q = v; q != p; ++q) 
      alloc.destroy(q);  /* destroy constructed elements */ 
     alloc.deallocate(v, n);  /* free memory */ 
     throw;      /* re-throw to signal constructor that failed */ 
    } 
} 

C++ ayırıcı olarak fiziksel bellek ayrıntılarından bellek ayrılamadı gerekir algoritma ve konteynerlerin uygulayıcıların yalıtmak için kullanılır. doğrudan uninitialized_fill kullanarak

Yaklaşım da alınabilir:

std::uninitialized_fill(v, v + n, val); /* copy elements with (placement new): 
              e g. void construct(pointer p, 
                    const T& val) 
              { ::new((void *)p) T(val); } */ 

Bu Bjarne Stroustrup yönettiği "C++ ... 3. baskı" daha ayrıntılarla anlatılmıştır. Here buna dayanan bir örnektir.

+1

+ 1'e teşekkür ederiz. OP'nin, vektör yeniden boyutlandırıldığında, eski dizideki öğeleri de yok etmesinin gerekeceği durum hakkında sorduğunu unutmayın. Ancak yukarıdaki kod anlaşıldıktan sonra bunu yapmak önemsizdir. – user4815162342