Yazılım Geliştirme: C ++ 17'de polimorfik tahsisatçı
Bu makale, C ++ 17: Allocaters Polimorfik'teki neredeyse bilinmeyen bir özellik yoluyla mini bir serinin başlangıcıdır. Sık sık polimorfik üzerine tahsisatçılar yazacağım söz verdim. Bugün sözümü çözüyorum.
Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.
C ++ 98'den beri, bellek atanması genellikle standart kütüphanenin kişiselleştirilmiş türleri veya kapları gereksinimlerine uyarlanmıştır. Örneğin, STL'nin ardışık ve ilişkisel kaplarının kaplarının varsayılan tahsis parametresine sahiptir. Örneğin, aşağıdaki satırlar konteynerlerin 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:
air<const Key, T>>>
class unordered_map;
Bellek varsayılan olarak yığın tarafından atanır, ancak bu varsayılan ayar her zaman mantıklı değildir. Genellikle farklı bir strateji kullanılmalıdır. İşte bazı fikirler:
C ++ 17'deki polimorfik tahsisler sayesinde çalışmanız çok daha basit olacaktır. Ayrıntılara girmeden önce bir tanıtım örneği sunmak istiyorum.
// polymorphicAllocator.cpp
#include <array>
#include <cstddef>
#include <memory_resource>
#include <vector>
int main() {
std::array<std::byte, 200> buf1; // (1)
std:
mr::monotonic_buffer_resource pool1{buf1.data(),
buf1.size()};
std:
mr::vector<int> myVec1{&pool1}; // (3)
for (int i = 0; i < 5; ++i) {
myVec1.push_back(i);
}
char buf2[200] = {}; // (2)
std:
mr::monotonic_buffer_resource pool2{std::data(buf2),
std::size(buf2)};
std:
mr::vector<int> myVec2{&pool2};
for (int i = 0; i < 200; ++i) {
myVec2.push_back(i);
}
}
Her şeyden önce yığın üzerindeki hafızayı istiyorum. Bu görev için yapabilirim byte-Aray (satır 1) OA char-Car kullanımı (satır 2). Ayrıca birini başlatırlar std
mr::monotonic_buffer Yığınta zaten talep edilen belleğin adresi ve boyutu ile. Son adım, std:
mr::vector Bu depolama kaynağını kullandı.
İsmin odasının üyesi pmr Polimorfik bellek kaynağı anlamına geliyor. Polimorfik tahsislerin tüm bileşenleri bu odada adlandırılmıştır. STL'nin kaplarında onların pmr-Birler. Kullanılan pmr-Anation sadece biri için bir takma ad std::vectorBu özel alakatörü kullanır. Aşağıdaki iki satır eşdeğerdir:
std:
mr::vector<int> myVec1{&pool1};
std::vector<int, std:
mr:
olymorphic_allocator<int>>
myVec1{&pool1};
Örnek olarak polymorphicAllocator.cpp Soru ortaya çıksın, 200'lü bir vektör gibi int'S myVec2 bir char-200 elementli olarak adapte olabilir. Cevap basit: std:
mr::new_delete_resource Yukarı akış yukarı akış yukarı akış olarak geri dönüş olarak kullanılır. C ++ 17, önceden tanımlanmış bazı depolama kaynakları sunar.
Ön -Definite Depolama Kaynakları
Bir sonraki makalelerde listelenen önceden tanımlanmış depolama kaynaklarını kullanacağım. Bu nedenle, kısa bir genel bakış var. Önceden tanımlanmış tüm depolama kaynakları arayüz sınıfından gelir std:
mr::memory_resource türev. Sınıf üç kamu işlevini sunar allocate,, deallocate VE is_equal İLE.
std
mr::memory_resource Sonuç olarak, özel sanal üyelerin üç işlevini sunar do_allocate,, do_deallocate VE do_is_equal A. Genel olarak, kişiselleştirilmiş bir depolama kaynağı, sanal üyelerin bu üç işlevinin üzerine yazar. Aşağıdaki önceden tanımlanmış depolama kaynakları aynı şekilde davranır:
std:
mr::new_delete_resource
Global işlevleri olan bir depolama kaynağına bir işaretçi döndürür new VE delete çağrılar. Aksi belirtilmedikçe standart depolama kaynağıdır.
std:
mr::null_memory_resource
Bir işaretçiyi sıfır depolama kaynağına döndürün. Bu tahsis deposunun bu depolanmasının kullanılması std::bad_alloc-İstisna. Bu depolama kaynağı, belleğin yığın üzerine tahsis etmemenizi garanti eder.
std:
mr::synchronized_pool_resource
Güvenli daha düşük bir parçalanmaya sahip bir depolama kaynağı oluşturan bir sınıf. Bu sınıf, standart kaynak için bir graver görevi görür.
std:
mr::unsynchronized_pool_resource
Güvenli olmayan daha düşük bir parçalanmaya sahip bir depolama kaynağı oluşturan bir sınıf. Bu sınıf, standart kaynak için bir graver görevi görür.
std:
mr::monotonic_buffer_resource
İsteğe bağlı olarak bir arabelleğe teslim edilebilen iş parçacığı güvenli değil, tutarlı bir depolama alanında depolama kaynaklarının oluşturulması için bir ders. Bu depolama kaynağı son derece hızlıdır ve sadece büyüyebilir. Nesneleri yok eder, ancak bellek çıkarmaz.
Önceki programda var polymorphicAllocator.cpp A std:
mr::monotonic_buffer ile byte-Aray (1) ve bir char-Aray (2) tampon olarak kullanılır. Ayrıca, taşıyıcı myVec2 Standart Tahsisatçı (Mountain Tahsisatörü) ile ek bellek std:
mr::new_delete_resource Alca.
Sırada ne var?
Tabii ki, bu teknik bir makaleydi. Bir sonraki makalemde teoriyi kullanacağım ve tahsislerinizi ve ayrıntılarınızı temsil eden yavaş bir depolama turu uygulayacağım.
(RME)
Bu makale, C ++ 17: Allocaters Polimorfik'teki neredeyse bilinmeyen bir özellik yoluyla mini bir serinin başlangıcıdır. Sık sık polimorfik üzerine tahsisatçılar yazacağım söz verdim. Bugün sözümü çözüyorum.

Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.
C ++ 98'den beri, bellek atanması genellikle standart kütüphanenin kişiselleştirilmiş türleri veya kapları gereksinimlerine uyarlanmıştır. Örneğin, STL'nin ardışık ve ilişkisel kaplarının kaplarının varsayılan tahsis parametresine sahiptir. Örneğin, aşağıdaki satırlar konteynerlerin 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:
class unordered_map;
Bellek varsayılan olarak yığın tarafından atanır, ancak bu varsayılan ayar her zaman mantıklı değildir. Genellikle farklı bir strateji kullanılmalıdır. İşte bazı fikirler:
- Belleğin atanması yığın yerine yığın üzerinde yapılmalıdır.
- Bellek atamalarının sayısı azaltılmalıdır.
- Bağlı bellek blokları, CPU önbelleğindeki depolamadan yararlanmak için kullanılmalıdır.
- Bellek atanmalı ancak serbest bırakılmamalıdır.
- Bir depolama havuzu kullanılmalıdır.
- Bellek atanması yapılmalıdır.
- Farklı veri türleri için farklı tahsisler kullanılmalıdır.
- Boyutu artarsa, bellek tahsisi stratejisi bir tür veri türü için değişmelidir.
C ++ 17'deki polimorfik tahsisler sayesinde çalışmanız çok daha basit olacaktır. Ayrıntılara girmeden önce bir tanıtım örneği sunmak istiyorum.
// polymorphicAllocator.cpp
#include <array>
#include <cstddef>
#include <memory_resource>
#include <vector>
int main() {
std::array<std::byte, 200> buf1; // (1)
std:
buf1.size()};
std:
for (int i = 0; i < 5; ++i) {
myVec1.push_back(i);
}
char buf2[200] = {}; // (2)
std:
std::size(buf2)};
std:
for (int i = 0; i < 200; ++i) {
myVec2.push_back(i);
}
}
Her şeyden önce yığın üzerindeki hafızayı istiyorum. Bu görev için yapabilirim byte-Aray (satır 1) OA char-Car kullanımı (satır 2). Ayrıca birini başlatırlar std
İsmin odasının üyesi pmr Polimorfik bellek kaynağı anlamına geliyor. Polimorfik tahsislerin tüm bileşenleri bu odada adlandırılmıştır. STL'nin kaplarında onların pmr-Birler. Kullanılan pmr-Anation sadece biri için bir takma ad std::vectorBu özel alakatörü kullanır. Aşağıdaki iki satır eşdeğerdir:
std:
std::vector<int, std:
myVec1{&pool1};
Örnek olarak polymorphicAllocator.cpp Soru ortaya çıksın, 200'lü bir vektör gibi int'S myVec2 bir char-200 elementli olarak adapte olabilir. Cevap basit: std:
Ön -Definite Depolama Kaynakları
Bir sonraki makalelerde listelenen önceden tanımlanmış depolama kaynaklarını kullanacağım. Bu nedenle, kısa bir genel bakış var. Önceden tanımlanmış tüm depolama kaynakları arayüz sınıfından gelir std:
std
std:
Global işlevleri olan bir depolama kaynağına bir işaretçi döndürür new VE delete çağrılar. Aksi belirtilmedikçe standart depolama kaynağıdır.
std:
Bir işaretçiyi sıfır depolama kaynağına döndürün. Bu tahsis deposunun bu depolanmasının kullanılması std::bad_alloc-İstisna. Bu depolama kaynağı, belleğin yığın üzerine tahsis etmemenizi garanti eder.
std:
Güvenli daha düşük bir parçalanmaya sahip bir depolama kaynağı oluşturan bir sınıf. Bu sınıf, standart kaynak için bir graver görevi görür.
std:
Güvenli olmayan daha düşük bir parçalanmaya sahip bir depolama kaynağı oluşturan bir sınıf. Bu sınıf, standart kaynak için bir graver görevi görür.
std:
İsteğe bağlı olarak bir arabelleğe teslim edilebilen iş parçacığı güvenli değil, tutarlı bir depolama alanında depolama kaynaklarının oluşturulması için bir ders. Bu depolama kaynağı son derece hızlıdır ve sadece büyüyebilir. Nesneleri yok eder, ancak bellek çıkarmaz.
Önceki programda var polymorphicAllocator.cpp A std:
Sırada ne var?
Tabii ki, bu teknik bir makaleydi. Bir sonraki makalemde teoriyi kullanacağım ve tahsislerinizi ve ayrıntılarınızı temsil eden yavaş bir depolama turu uygulayacağım.
(RME)