2016-05-18 26 views
5

Top 10 dumb mistakes to avoid with C++11 smart pointer okuyordum. Numara 5. okur:Tüm durumlarda, shared_ptr yapımı için ham işaretçiye neden izin verilir?

Hata # 5: oluşturulduğu kısa sürede gibi bir shared_ptr bir nesne (ham işaretçi) atama değil! hemen

Kullanım make_shared veya new ve onunla işaretçi inşa:

int main() 
{ 
    Aircraft* myAircraft = new Aircraft("F-16"); 
    shared_ptr<aircraft> pAircraft(myAircraft); 
    ... 
    shared_ptr<aircraft> p2(myAircraft); 
    // will do a double delete and possibly crash 
} 

ve öneri gibi bir şeydir.

Tamam, bu konuda hiçbir şüphe sorun ve öneri. Ancak ben shared_ptr tasarımı hakkında bir sorum var. Bu çok kolay bir hata yapmak ve shared_ptr tüm "güvenli" tasarımı çok kolay yanlışlıklar tarafından atılabilir.

Şimdi soru, bu kolayca ham işaretçi sadece yapıcı bir r-değeri referanstan olacaktır ki burada shared_ptr alternatif bir tasarım ile sabit olabilir mı? Bu şekilde shared_ptr yılında

template<class T> 
struct shared_ptr{ 
    shared_ptr(T*&& t){...basically current implementation...} 
    shared_ptr(T* t) = delete; // this is to... 
    shared_ptr(T* const& t) = delete; // ... illustrate the point. 
    shared_ptr(T*& t) = delete; 
    ... 
}; 

sadece new sonucu ya da bazı fabrika işlevinden başlatıldı edilebilir. Bu kütüphanede C++ dilinin bir underexploitation

mi? veya ne ham işaretçi (l-değeri) referanstan bir kurucu sahip noktası bu büyük ihtimalle yanlış kullanımı olacak ise?

bu tarihsel rastlantı mıdır? (örneğin, r değeri referansları verilmeden önce paylaşılan_ptr önerildi, vb.) Geriye dönük uyumluluk?

(Tabi denebilir std::shared_ptr<type>(std::move(ptr)); o yakalamak için daha kolay ve ayrıca çalışma bu gerçekten gerekli mi etrafında eğer. Olduğunu)

Ben bir şey eksik?

cevap

4

İşaretçiler kopyalamak çok kolaydır. R-değeri referansı ile kısıtlama yapsanız bile, güvenlik kurulumunu geçersiz kılacak kopyalar kolaylıkla (bir işaretçiyi bir işlev parametresi olarak geçirdiğinizde olduğu gibi) yapabilirsiniz. Üstelik, kolayca T* const veya T*& türlerine sahip olabileceğiniz ve tür uyumsuzluğunu alabileceğiniz şablonlarda sorunlara gireceksiniz.

Yani onu başlamak için standart değildi muhtemel neden olan önemli güvenlik kazanımlar olmadan daha fazla kısıtlamalar oluşturmak öneriyorlar.

make_shared noktası ortak bir ibrenin inşaat atomize etmektir. f(shared_ptr<int>(new int(5)), throw_some_exception()) olduğunu söyle. Parametre çağırma sırası, standart tarafından garanti edilmez. Derleyicinin yeni bir int oluşturmasına izin verilir, throw_some_exception'u çalıştırın ve sonra int (eğer throw_some_exception aslında bir istisna atarsa) sızmanız anlamına gelen shared_ptr öğesini yapılandırın. make_shared sadece nesnenin ve paylaşılan işaretçinin kendi içinde yaratılmasını sağlar, bu da derleyicinin düzeni değiştirmesine izin vermez, böylece güvenli olur.Eğer make_shared() aramak mümkün olmayabilir hangi durumlarda bir dizi var

+0

İşaretçiler kopyalamak için kolay, ancak bir 'shared_ptr' için vardır. 'T * const' veya' T * & 'her ikisi de silinecektir, bu yüzden" tip uyuşmazlıkları "hakkındaki noktanızı anlamıyorum. (Ayrıca şablonda kesinti yapıcıda gerçekleşmez.) 'Make_shared' kullanımını sorgulamıyorum, aksine, bu onu kullanmaya teşvik ederdi. – alfC

+0

Son olarak, yapıcısı yapmak gibi, ayrı bir çözüm gereken belki ayrı bir problem olarak görünüyor işlev çağırma atılan hariç senaryoda, ilgili noktayı anlamıyorum 'özel shared_ptr' ve bir arkadaşı işlevi zorlamak 'shared_ptr' oluşturmanın tek yolu 'make_shared'. – alfC

+0

@alfC 'X * a = new X; X * b = a; shared_ptr (a); shared_ptr (b) 'Bu, işaretçi kopyası örneğidir. Veya X * a = yeni X olabilir; f (a) ' Shared_ptr (a) '' burada 'f (x * a_copy) {Shared_ptr (a_copy); } '. T && kurucu ile kısıtlama yapsak bile, sadece yukarıdaki kod, eskisi gibi derler ve başarısız olur. Hatalı eşleşmeler için – Sorin

1

. Örneğin, kodunuz söz konusu sınıfı ayırmak ve oluşturmaktan sorumlu olmayabilir. Aşağıdaki paradigma (özel kurucular + fabrika fonksiyonları) çeşitli nedenlerle bazı C++ kod üsleri kullanılır: Eğer sopa isteseydiniz, bu durumda

struct A { 
    private: 
    A(); 
}; 

A* A_factory(); 

A* bir shared_ptr<> içine A_factory() aldığım, sen 'make_shared() yerine ham bir işaretçi alan kurucuyu kullanmak zorundayım. Başımın Kapalı

, diğer bazı örnekler: Sen posix_memalign() kullanarak türü için hizalanmış bellek almak ve sonra free() çağıran özel deleter ile shared_ptr<> depolamak isteyen

  • (bu kullanım örneği diline hizalı bir tahsis eklediğimizde yakında gideceğiz!).
  • mmap() ile oluşturulan bellek eşlemeli bir bölgeye shared_ptr<> içine munmap() çağrıları yapan özel bir silme işlemiyle işaret etmek istersiniz (bu kullanım durumu, shmem için standartlaştırılmış bir özellik elde ettiğimizde gider; önümüzdeki birkaç ay içinde çalışın).
  • Özel bir deleter ile shared_ptr<> içine tarafından tahsis edilen bir işaretçi sopa istiyorum. `T * &&` sadece yapıcı ise
+0

Fabrikaların lehindeyim. Asıl sorum ise, shared_ptr yapıcısı hakkındadır, bu yüzden sadece fabrikalardan, make_shared veya başka bir şekilde girdileri kabul eder. – alfC