polymorphic_allocator: ne zaman ve neden kullanmalıyım?


122

İşte cppreference ile ilgili belgeler , işte çalışma taslağı.

Gerçek amacının ne olduğunu polymorphic_allocatorve onu ne zaman / neden / nasıl kullanmam gerektiğini anlamadığımı itiraf etmeliyim .
Örnek olarak, pmr::vectoraşağıdaki imzaya sahiptir:

namespace pmr {
    template <class T>
    using vector = std::vector<T, polymorphic_allocator<T>>;
}

polymorphic_allocatorTeklif ne ? std::pmr::vectorEski moda konusunda da ne teklif var std::vector? Şimdiye kadar yapamadığım için şimdi ne yapabilirim?
Bu ayırıcının gerçek amacı nedir ve gerçekte ne zaman kullanmalıyım?


1
allocator<T>Doğal olarak sahip olduğu bazı sorunların üstesinden gelmeye çalışırlar . Dolayısıyla, ayırıcıları sık sık kullanırsanız, bunun değerini göreceksiniz.
edmz

2
İlgili kağıt .
edmz

Yanıtlar:


103

Cppreference'den seçim teklifi:

Bu çalışma zamanı polimorfizmi, polymorphic_allocator kullanan nesnelerin, aynı statik ayırıcı türüne rağmen çalışma zamanında farklı ayırıcı türleri kullanmış gibi davranmasına izin verir.

"Normal" ayırıcılarla ilgili sorun, kabın türünü değiştirmeleridir. vectorBelirli bir ayırıcıya sahip olmak istiyorsanız , Allocatorşablon parametresini kullanabilirsiniz:

auto my_vector = std::vector<int,my_allocator>();

Şimdi sorun, bu vektörün farklı bir ayırıcıya sahip bir vektör ile aynı tipte olmamasıdır. Örneğin, varsayılan ayırıcı vektörü gerektiren bir işleve geçemezsiniz veya aynı değişkene / işaretçiye farklı bir ayırıcı tipine sahip iki vektör atayamazsınız, örneğin:

auto my_vector = std::vector<int,my_allocator>();
auto my_vector2 = std::vector<int,other_allocator>();
auto vec = my_vector; // ok
vec = my_vector2; // error

Bir polimorfik ayırıcı, ayırıcı davranışını şablon mekanizma yerine dinamik gönderme yoluyla tanımlayabilen bir üyeye sahip tek bir ayırıcı tipidir. Bu, belirli, özelleştirilmiş tahsis kullanan, ancak yine de ortak türde olan konteynerlere sahip olmanızı sağlar.

Ayırıcı davranışının özelleştirilmesi, ayırıcıya bir std::memory_resource *:

// define allocation behaviour via a custom "memory_resource"
class my_memory_resource : public std::pmr::memory_resource { ... };
my_memory_resource mem_res;
auto my_vector = std::pmr::vector<int>(0, &mem_res);

// define a second memory resource
class other_memory_resource : public std::pmr::memory_resource { ... };
other_memory_resource mem_res_other;
auto my_other_vector = std::pmr::vector<int>(0, &mes_res_other);

auto vec = my_vector; // type is std::pmr::vector<int>
vec = my_other_vector; // this is ok -
      // my_vector and my_other_vector have same type

Geriye kalan ana sorun, gördüğüm kadarıyla, bir std::pmr::konteynerin hala std::varsayılan ayırıcı kullanan eşdeğer konteyner ile uyumlu olmamasıdır . Bir kapsayıcıyla çalışan bir arayüz tasarlarken bazı kararlar vermeniz gerekir:

  • Aktarılan kapsayıcı özel tahsis gerektirebilir mi?
  • eğer öyleyse, bir şablon parametresi eklemeli miyim (rastgele ayırıcılara izin vermek için) veya bir polimorfik ayırıcı kullanımını zorunlu kılmalı mıyım?

Bir şablon çözümü, bir polimorfik ayırıcı da dahil olmak üzere herhangi bir ayırıcıya izin verir , ancak başka dezavantajlara sahiptir (oluşturulan kod boyutu, derleme süresi, kod başlık dosyasında açığa çıkarılmalıdır, problemi dışa doğru itmeye devam eden daha fazla "tip kirliliği" potansiyeli). Öte yandan bir polimorfik ayırıcı çözeltisi, bir polimorfik ayırıcının kullanılması gerektiğini belirtir . Bu, kullanmayı engellerstd:: , varsayılan ayırıcı kapların kullanılmasını engeller ve eski kodla arabirim oluşturmaya yönelik etkileri olabilir.

Normal bir ayırıcı ile karşılaştırıldığında, bir polimorfik ayırıcının, memory_resource işaretçisinin depolama ek yükü (ki bu büyük olasılıkla ihmal edilebilir) ve tahsisler için sanal işlev gönderiminin maliyeti gibi bazı küçük maliyetleri vardır. Esas sorun, muhtemelen, polimorfik ayırıcılar kullanmayan eski kodla uyumsuzluktur.


2
Öyleyse, std::pmr::sınıflar için ikili düzen büyük olasılıkla farklı mı?
Euri Pinhollow

12
@EuriPinhollow, sorduğunuz buysa ve reinterpret_castarasında olamaz . std::vector<X>std::pmr::vector<X>
davmac

4
Bellek kaynağının bir çalışma zamanı değişkenine bağlı olmadığı basit durumlar için, iyi bir derleyici sanallaştırılır ve sonuçta fazladan maliyet olmaksızın çok biçimli bir ayırıcı elde edersiniz (gerçekten bir sorun olmayan göstericiyi depolamak dışında). Bahsetmeye değer olduğunu düşündüm.
DeiDei

1
@ Yakk-AdamNevraumont "bir std::pmr::konteyner, std::varsayılan ayırıcı kullanan eşdeğer konteyner ile hala uyumlu değildir " . Birinden diğerine tanımlanmış bir atama operatörü de yoktur. Şüpheye düştüğünüzde deneyin: godbolt.org/z/Q5BKev (kod tam olarak yukarıdaki gibi değildir çünkü gcc / clang "deneysel" bir ad alanında polimorfik ayırma sınıflarına sahiptir).
davmac

1
@davmac Ah, yani bir template<class OtherA, std::enable_if< A can be constructed from OtherA > vector( vector<T, OtherA>&& )kurucu yok. Kararsızdım ve TS uyumlu pmr'ye sahip bir derleyiciyi nerede bulacağımı bilmiyordum.
Yakk - Adam Nevraumont

33

polymorphic_allocator özel bir ayırıcı için std::functionbir doğrudan işlev çağrısında olduğu .

Bildirim noktasında hangisine karar vermek zorunda kalmadan konteynerinizle bir ayırıcı kullanmanıza izin verir. Dolayısıyla, birden fazla ayırıcının uygun olacağı bir durumunuz varsa,polymorphic_allocator .

Belki arayüzünüzü basitleştirmek için hangi ayırıcının kullanıldığını gizlemek istersiniz veya belki onu farklı çalışma zamanı durumları için değiştirebilmek istersiniz.

Öncelikle bir ayırıcıya ihtiyaç duyan bir koda ihtiyacınız var, sonra pmr vektörünü düşünmeden önce hangisinin kullanıldığını değiştirebilmeyi istemelisiniz.


7

Polimorfik ayırıcıların bir dezavantajı polymorphic_allocator<T>::pointer, her zaman adil olmasıdır T*. Bu, onları süslü işaretçilerle kullanamayacağınız anlamına gelir . Eğer a öğesinin öğelerini vectorpaylaşılan belleğe yerleştirmek ve bunlara boost::interprocess::offset_ptrs aracılığıyla erişmek gibi bir şey yapmak istiyorsanız , bunun için normal, polimorfik olmayan bir ayırıcı kullanmanız gerekir.

Bu nedenle, polimorfik ayırıcılar, bir kapsayıcının statik türünü değiştirmeden tahsis davranışını değiştirmenize izin verse de , tahsisin ne olduğunu sınırlar .


2
Bu önemli bir nokta ve büyük bir serseri. Arthur O'Dwyer'in Anlamlı süslü işaretçilerine Doğru , "c ++ 17
STL'de Ustalaşmak

polimorfik ayırıcı kullanımının gerçek dünya kullanım durumunu verebilir misiniz?
darune
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.