bir diziyle paylaşılan_ptr: kullanılmalı mı?


172

İle ilgili sadece küçük bir sorgu shared_ptr .

shared_ptrBir diziyi göstermeyi kullanmak iyi bir uygulama mı? Örneğin,

shared_ptr<int> sp(new int[10]);

Eğer değilse, peki neden değil? Zaten farkında olduğum bir nedeni, arttıramaz / azaltamaz shared_ptr. Bu nedenle, bir diziye normal bir işaretçi gibi kullanılamaz.


2
FWIT, sadece kullanmayı düşünebilirsiniz std::vector. Diziyi, kopyaları oluşturmamak için referansları kullanarak geçirmeye dikkat etmelisiniz. Verilere erişmek için sözdizimi shared_ptr'den daha temizdir ve yeniden boyutlandırmak çok kolaydır. Ve eğer istersen bütün STL iyiliğini elde edersin.
— Nicu Stiurca

6
Dizinin boyutu derleme zamanında belirlenirse, kullanmayı da düşünebilirsiniz std::array. Bu ise hemen hemen en kütüphane bileşenleri içinde kullanım için uygun bir anlam ile değil, bir ham dizisi ile aynı. Özellikle bu tür nesneler yok edilir delete, yok edilir delete[]. Ve aksine vector, verileri doğrudan nesnede saklar, böylece ekstra tahsis almazsınız.
— celtschk

Yanıtlar:


268

İle C ++ 17 , shared_ptrdinamik olarak atanan diziyi yönetmek için kullanılabilir. shared_ptrBu durumda şablon argümanı olmalı T[N]ya T[]. Yani yazabilirsin

shared_ptr<int[]> sp(new int[10]);

N4659'dan [util.smartptr.shared.const]

  template<class Y> explicit shared_ptr(Y* p);

Gereksinimler: Y tam tip olmalıdır. İfadesi delete[] p, ne zaman Tbir dizi türüdür veya delete pzaman Tbir dizi türü değil, davranışı iyi tanımlanmış sahip olacaktır ve istisnalar atmak olmayacaktır.
...
Açıklamalar: zaman Tbir dizi türü ifade olmadıkça, bu yapıcı aşırı çözünürlük katılamaz delete[] piyi oluşturulmuş olan ve her iki Tolduğu U[N]ve Y(*)[N]dönüştürülebilen T*ya da Tbir U[]ve Y(*)[]dönüştürülebilen T*. ...

Bunu desteklemek için üye türü element_typeşimdi

using element_type = remove_extent_t<T>;

Dizi öğelerine erişim operator[]

  element_type& operator[](ptrdiff_t i) const;

Gerektirir: get() != 0 && i >= 0 . Eğer Tbir U[N], i < N. ...
Notlar: Bir Tdizi türü olmadığında, bu üye işlevinin bildirilip bildirilmediği belirtilmez. Eğer ilan edilirse, fonksiyonun beyanının (mutlaka tanımı olmamasına rağmen) iyi bir şekilde oluşturulması dışında, dönüş türünün ne olduğu belirtilmemiştir.


Önceki C ++ 17 , shared_ptrolabilir değil dinamik olarak ayrılmış dizilerini yönetmek için kullanılabilir. Varsayılan olarak, yönetilen nesneyi artık başvuru kalmadığında shared_ptrçağırır delete. Bununla birlikte, kullanarak ayırdığınızda , kaynağı boşaltmak için değil new[]aramanız gerekir .delete[]delete

shared_ptrBir diziyle doğru şekilde kullanabilmek için özel bir silici sağlamanız gerekir.

template< typename T >
struct array_deleter
{
  void operator ()( T const * p)
  { 
    delete[] p; 
  }
};

Shared_ptr dosyasını aşağıdaki gibi oluşturun:

std::shared_ptr<int> sp(new int[10], array_deleter<int>());

Şimdi yönetilen nesneyi yok ederken shared_ptrdoğru şekilde arayacaktır delete[].

Yukarıdaki özel silme ile değiştirilebilir

  • std::default_deleteDizi türleri için kısmi uzmanlık

    std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
  • lambda ifadesi

    std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });

Ayrıca, yönetilen nesnenin paylaşımına gerçekten ihtiyaç duymadığınız sürece, a unique_ptr, dizi türleri için kısmi bir uzmanlığa sahip olduğundan bu görev için daha uygundur.

std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]

C ++ Kütüphane Temelleri Uzantıları tarafından yapılan değişiklikler

Başka bir ön-C ++ tarafından sağlanan, yukarıda sıralananlara 17 Alternatif Kütüphane Temel Teknik Şartname artar, shared_ptrbu nesneleri bir dizi sahip zaman durumlarda kutunun dışında çalışmasına izin vermek için. shared_ptrBu TS için geçerli değişikliklerin mevcut taslağı N4082'de bulunabilir . Bu değişikliklere std::experimentalad alanı üzerinden erişilebilir ve <experimental/memory>başlığa dahil edilir . shared_ptrDizileri desteklemeye yönelik ilgili değişikliklerden bazıları şunlardır:

- Üye türünün tanımı element_type değişir

typedef T element_type;

 typedef typename remove_extent<T>::type element_type;

- Üye operator[]ekleniyor

 element_type& operator[](ptrdiff_t i) const noexcept;

- farklı unique_ptrdiziler için kısmi uzmanlık, her ikisi de shared_ptr<T[]>ve shared_ptr<T[N]>geçerli olur ve hem de neden olur delete[]nesnelerin idare dizi olarak adlandırılır.

 template<class Y> explicit shared_ptr(Y* p);

Gereksinimler : Ytam tip olmalıdır. İfade delete[] p, ne zaman Tbir dizi türü, ya da delete pzaman, Tbir dizi türü değil, iyi biçimli olacaktır iyi davranış tanımlanmış eder, ve kural dışı durumlar olmamalıdır. Tüm Tolup U[N], Y(*)[N]dönüştürülebilir olacaktır T*; zaman Tolduğu U[], Y(*)[]dönüştürülebilir olacaktır T*; aksi takdirde Y*dönüştürülebilir olmalıdır T*.


9
+1, açıklama: Ayrıca Boost's var shared-array.
— jogojapan

5
@ tshah06 shared_ptr::get, yönetilen nesneye bir işaretçi döndürür. Yani kullanabilirsinizsp.get()[0] = 1; ... sp.get()[9] = 10;
— Praetorian

55
ALT: std::shared_ptr<int> sp( new int[10], std::default_delete<int[]>() );ayrıca bkz. En.cppreference.com/w/cpp/memory/default_delete
— yohjp

2
@Jeremy Boyut derleme zamanında biliniyorsa bunun için bir sınıf yazmaya gerek yoktur, std::shared_ptr<std::array<int,N>>yeterli olmalıdır.
— Praetorian

13
Neden unique_ptrbu kısmi uzmanlığı elde ediyor ama shared_ptralmıyor?
— Adam

28

Kullanabileceğiniz daha kolay bir alternatif shared_ptr<vector<int>>.


5
Evet öyle. Veya bir vektör, bir dizinin üst kümesidir - aynı bellek içi temsiline (artı meta veri) sahiptir, ancak yeniden boyutlandırılabilir. Gerçekten bir dizi istediğiniz ancak vektör kullanamayacağınız durumlar yoktur.
— Timmmm

2
Buradaki fark, vektör boyutunun artık statik olması ve verilere erişimin çift dolaylı olarak yapılmasıdır. Performans kritik bir sorun değilse, bu işe yarar, aksi takdirde bir dizinin paylaşılmasının kendi nedeni olabilir.
— Emilio Garavaglia

4
O zaman muhtemelen kullanabilirsiniz shared_ptr<array<int, 6>>.
— Timmmm

10
Diğer fark, ham bir diziden biraz daha büyük ve yavaş olmasıdır. Genellikle gerçekten bir sorun değil ama 1 == 1.1 gibi davranmayalım.
— Andrew

2
Dizideki verilerin kaynağının, bir vektöre dönüştürmenin gereksiz veya gereksiz olduğu anlamına geldiği durumlar vardır; örneğin bir kameradan çerçeve alırken. (Ya da bu benim anlayışım zaten)
— Narfanator
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.