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.