Yazılım geliştirme: C++17’de polimorfik ayırıcılar

Adanali

Active member
Yazılım geliştirme: C++17’de polimorfik ayırıcılar
Bu makale, C++17’deki neredeyse bilinmeyen bir özellik olan polimorfik ayırıcılarla ilgili bir mini dizinin başlangıcıdır. Polimorfik ayırıcılar hakkında yazacağıma sık sık söz verdim. Bugün sözümü tutuyorum.

Duyuru








Rainer Grimm uzun yıllardır yazılım mimarı, ekip ve eğitim yöneticisi olarak çalışmaktadır. C++, Python ve Haskell programlama dilleri üzerine makaleler yazmaktan hoşlanıyor, aynı zamanda özel konferanslarda sık sık konuşmaktan da hoşlanıyor. Modern C++ adlı blogunda C++ tutkusunu yoğun bir şekilde ele alıyor.







C++98’den bu yana, genel olarak bellek ayırmanın yanı sıra standart kitaplıktaki kullanıcı tanımlı türler veya kapsayıcılar için de bellek ayırma, tam olarak ihtiyaçlarınıza göre uyarlanabilir. Örneğin, STL sıralı ve ilişkisel kapların varsayılan bir tahsis parametresi vardır. Aşağıdaki satırlar örnek olarak konteyner bildirimini göstermektedir std::string, std::vector VE std::unordered_map:


template<class CharT, class Traits = std::char_traits<CharT>,
class Allocator = std::allocator<CharT>>
class basic_string;
using string = basic_string<char>;

template<class T, class Allocator = std::allocator<T>>
class vector;

template<class Key, class T, class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>>
class unordered_map;



Varsayılan olarak bellek yığından ayrılır, ancak bu varsayılan her zaman anlamlı değildir. Çoğunlukla farklı bir strateji kullanılmalıdır. İşte bazı fikirler:

  • Bellek tahsisi yığın yerine yığın üzerinde gerçekleşmelidir.
  • Bellek tahsislerinin sayısı azaltılmalıdır.
  • CPU önbelleğe alma özelliğinden yararlanmak için bitişik bellek blokları kullanılmalıdır.
  • Bellek tahsis edilmeli ancak serbest bırakılmamalıdır.
  • Depolama havuzu kullanmanız gerekir.
  • Bellek ayırma iş parçacığı açısından güvenli olmalıdır.
  • Farklı veri türleri için farklı ayırıcılar kullanmanız gerekir.
  • Bellek ayırma stratejisinin, boyutu arttıkça veri türü için değişmesi kaçınılmazdır.
C++98 ile zaten kendi bellek ayırıcınızı uygulayıp kullanabiliyordunuz, ancak bu oldukça zordu ve hataya açıktı. C++’da bellek ayırıcılar hakkında zaten iki makale yazdım: “Std::allocator ile Bellek İsteği” ve Jonathan Müller’in misafir yazısı: “Bellek Havuzu Ayırıcılar”.

C++17’deki polimorfik ayırıcılar sayesinde işiniz çok daha kolay olacaktır. Detaylara girmeden önce giriş niteliğinde bir örnek vermek istiyorum.


// polymorphicAllocator.cpp

#include <array>
#include <cstddef>
#include <memory_resource>
#include <vector>

int main() {

std::array<std::byte, 200> buf1; // (1)
std::pmr::monotonic_buffer_resource pool1{buf1.data(),
buf1.size()};
std::pmr::vector<int> myVec1{&pool1}; // (3)
for (int i = 0; i < 5; ++i) {
myVec1.push_back(i);
}

char buf2[200] = {}; // (2)
std::pmr::monotonic_buffer_resource pool2{std::data(buf2),
std::size(buf2)};
std::pmr::vector<int> myVec2{&pool2};
for (int i = 0; i < 200; ++i) {
myVec2.push_back(i);
}

}


İlk önce yığında hafıza talep ediyorum. Bu görev için yapabilirim byte-Dizi (satır 1) oa char-Dizi (satır 2). Ben de bir tane başlatıyorum std:pmr::monotonic_buffer gerekli adres ve bellek boyutu yığında zaten var. Bu son adım std::pmr::vector bu depolama kaynağını kullanır.

Ad alanı bileşeni pmr polimorfik bellek kaynağı anlamına gelir. Polimorfik ayırıcıların tüm bileşenleri bu ad alanında bulunur. STL konteynerlerinin kendilerine ait pmrkarşı taraflar. Kullanılan pmr-Pendant sadece bir kişinin takma adıdır std::vector, özel ayırıcıyı kullanan. Aşağıdaki iki satır eşdeğerdir:


std::pmr::vector<int> myVec1{&pool1};

std::vector<int, std::pmr::polymorphic_allocator<int>>
myVec1{&pool1};



Örnekte polymorphicAllocator.cpp Bir vektörün 200 ile nasıl çalıştığı sorusu ortaya çıkabilir. int‘S myVec2 birinde char-Dizi 200 eleman içerebilir. Cevap basit: std::pmr::new_delete_resource Geri dönüş olarak yukarı akış ayırıcısı adı verilen bir ayırıcı kullanılır. C++17 bazı varsayılan bellek kaynaklarını sağlar.

Varsayılan depolama kaynakları


Sonraki yazılarda listelenen varsayılan depolama kaynaklarını uygulayacağım. İşte hızlı bir genel bakış. Tüm varsayılan depolama kaynakları arayüz sınıfına aittir std::pmr::memory_resource türev. Sınıf üç genel işlev sağlar allocate, deallocate VE is_equal İLE.

std:pmr::memory_resource sonuç olarak üç özel sanal üyelik özelliği sunar do_allocate, do_deallocate VE do_is_equal C. Genellikle özel bir depolama bu üç sanal üye işlevini geçersiz kılar. Aşağıdaki varsayılan depolama kaynakları aynı şekilde davranır:

std::pmr::new_delete_resource

genel işlevleri içeren bir bellek kaynağına bir işaretçi döndürür new VE delete Aramalar. Aksi belirtilmediği sürece bu varsayılan depolamadır.

std::pmr::null_memory_resource

boş bellek kaynağına bir işaretçi döndürür. Tahsis için bu bellek kaynağının kullanılması, std::bad_alloc-İstisna. Bu bellek kaynağı, belleğin yığın üzerinde rastgele ayrılmamasını sağlar.

std::pmr::synchronized_pool_resource

İş parçacığı açısından güvenli, daha az parçalanmaya sahip bir bellek kaynağı oluşturan bir sınıf. Bu sınıf, varsayılan kaynak için sarmalayıcı görevi görür.

std::pmr::unsynchronized_pool_resource

İş parçacığı açısından güvenli olmayan, daha az parçalanmaya sahip bir bellek kaynağı oluşturan bir sınıf. Bu sınıf, varsayılan kaynak için sarmalayıcı görevi görür.

std::pmr::monotonic_buffer_resource

İsteğe bağlı olarak bir arabelleğin aktarılabileceği bitişik, iş parçacığı açısından güvenli olmayan bir bellek alanında bellek kaynakları oluşturmaya yönelik bir sınıf. Bu depolama son derece hızlıdır ve yalnızca büyüyebilir. Nesneleri yok eder ancak hafızayı boşaltmaz.

Bir önceki programda vardı polymorphicAllocator.cpp A std::pmr::monotonic_buffer Birlikte byte-Array(1) ve bir char-Array (2) arabellek olarak kullanılır. Ayrıca, taşıyıcının myVec2 standart ayırıcıyla ek bellek (yukarı akış ayırıcı) std::pmr::new_delete_resource atandı.

Sıradaki ne?


Tabii bu teknik bir yazıydı. Bir sonraki makalemde teoriyi uygulayacağım ve tahsislerini ve serbest tahsislerini temsil eden bir depolama kaynağı uygulayacağım.


(kendim)



Haberin Sonu
 
Üst