Yazılım Geliştirme: C++20'de std::span: daha fazla ayrıntı

Adanali

Active member
Yazılım Geliştirme: C++20'de std::span: daha fazla ayrıntı


  1. Yazılım Geliştirme: C++20'de std::span: daha fazla ayrıntı

Bugün pek bilinmeyen özelliklerinden bahsetmek istiyorum. std::span ve tehlikeleri yazın. Bu aynı zamanda ALS araştırması için de kişisel bir endişe kaynağıdır.

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.













A std::spanBazen görme denilen şey asla bir sahip değildir. Bu bitişik bellek basit bir dizi, belirli bir boyuttaki bir işaretçi olabilir std::array, A std::vector ah std::string Olmak. Tipik bir uygulama, ilk elemanına ve bir boyuta işaret eden bir işaretçiden oluşur. Birinin ana nedeni std::span<T> şudur: bir C dizisi, bir işleve aktarıldığında ilk öğesini gösteren bir işaretçiye indirgenir. Bu, dizinin boyutunu kaybetmesine neden olur. Bu bozulma, C/C++'daki hataların tipik bir nedenidir.

Boyut otomatik olarak belirlenir


Tam tersine yönlendiriyor. std::span<T> otomatik olarak bağlantılı nesne dizilerinin boyutu.


// printSpan.cpp&#13;
&#13;
#include <iostream>&#13;
#include <vector>&#13;
#include <array>&#13;
#include <span>&#13;
&#13;
void printMe(std::span<int> container) {&#13;
&#13;
std::cout << "container.size(): " << container.size() << 'n'; // (4)&#13;
for(auto e : container) std::cout << e << ' ';&#13;
std::cout << "nn";&#13;
}&#13;
&#13;
int main() {&#13;
&#13;
std::cout << std::endl;&#13;
&#13;
int arr[]{1, 2, 3, 4}; // (1)&#13;
printMe(arr);&#13;
&#13;
std::vector vec{1, 2, 3, 4, 5}; // (2)&#13;
printMe(vec);&#13;
&#13;
std::array arr2{1, 2, 3, 4, 5, 6}; // (3)&#13;
printMe(arr2);&#13;
&#13;
}


C(1) dizisi, std::vector (2) ve bu std::array (3) kendi intS. Sonuç olarak şunları içerir: std::span Ayrıca intS. Bu basit örnekte ilginç bir şey daha var. Her kutu konteyneri için std::span boyutunu (4) elde edin.








Bu kısa bir hatırlatmaydı std::span. Diğer her şeyi önceki makalem olan “C++20: Std::span ile Nesne Dizilerine Güvenli Erişim” bölümünde bulabilirsiniz.

Bir std::span'ın statik veya dinamik bir aralığı olabilir.

Statik ve dinamik uzantı


Varsayılan olarak std::span dinamik bir uzantı:


template <typename T, std::size_t Extent = std::dynamic_extent>&#13;
class span;


Zaman std::span statik bir uzantıya sahiptir, boyutu derleme zamanında bilinir ve veri türünün bir parçasıdır: std::span. Bu nedenle bunların uygulanması yalnızca bitişik nesneler dizisinin ilk öğesine bir işaretçiye ihtiyaç duyar.

Birinin uygulanması std::span Dinamik uzantılı, ilk öğeye işaret eden bir işaretçiden ve bitişik nesne dizisinin boyutundan oluşur. Boyut bunun bir parçası değil std::span-adam.

Bir sonraki örnek, iki yayılma türü arasındaki farkları göstermektedir.


// staticDynamicExtentSpan.cpp&#13;
&#13;
#include <iostream>&#13;
#include <span>&#13;
#include <vector>&#13;
&#13;
void printMe(std::span<int> container) { // (3) &#13;
&#13;
std::cout << "container.size(): " << container.size() << 'n';&#13;
for (auto e : container) std::cout << e << ' ';&#13;
std::cout << "nn";&#13;
}&#13;
&#13;
int main() {&#13;
&#13;
std::cout << 'n';&#13;
&#13;
std::vector myVec1{1, 2, 3, 4, 5}; &#13;
std::vector myVec2{6, 7, 8, 9};&#13;
&#13;
std::span<int> dynamicSpan(myVec1); // (1)&#13;
std::span<int, 4> staticSpan(myVec2); // (2)&#13;
&#13;
printMe(dynamicSpan);&#13;
printMe(staticSpan);&#13;
&#13;
// staticSpan = dynamicSpan; ERROR // (4)&#13;
dynamicSpan = staticSpan; // (5) &#13;
&#13;
printMe(staticSpan); // (6)&#13;
&#13;
std::cout << 'n';&#13;
&#13;
}


dynamicSpan (1) dinamik bir uzantıya sahipken, staticSpan (2) statik bir taneye sahiptir. İkisi birden std::spanfonksiyonda boyutlarını verirler printMe (3) geri. A std::span statik uzantıyla şunları yapabilirsiniz std::span dinamik uzantıyla atanabilir ancak bunun tersi mümkün değildir. (4) hataya neden olur, ancak (5) ve (6) geçerlidir.








Özel bir kullanım durumu var std::span. Bir std::span sabit bir düzenlenebilir öğe aralığı olabilir.

Sürekli değişen öğeler dizisi


Kolaylık sağlamak için bir tanesinden bahsedeceğim std::vector biridir std::span Alan. A std::vector değişen bir dizi değişken öğeyi modeller: std::vector. Eğer buna sahipsen std::vector GİBİ const beyan edilen, sabit bir dizi sabit nesneyi modeller: const std::vector. Sabit bir dizi düzenlenebilir öğeyi modellemek mümkün değildir. Bu noktada gelir std::span oyunda. A std::span sabit bir dizi değiştirilebilir nesneyi modeller: std::span. Aşağıdaki şekilde alanlar (sabit/düzenlenebilir) ve öğeler (sabit/düzenlenebilir) arasındaki farklar gösterilmektedir.








// constRangeModifiableElements.cpp&#13;
&#13;
#include <iostream>&#13;
#include <span>&#13;
#include <vector>&#13;
&#13;
void printMe(std::span<int> container) {&#13;
&#13;
std::cout << "container.size(): " << container.size() << 'n'; &#13;
for (auto e : container) std::cout << e << ' ';&#13;
std::cout << "nn";&#13;
}&#13;
&#13;
int main() {&#13;
&#13;
std::cout << 'n';&#13;
&#13;
std::vector<int> origVec{1, 2, 2, 4, 5};&#13;
&#13;
// Modifiable range of modifiable elements&#13;
std::vector<int> dynamVec = origVec; // (1)&#13;
dynamVec[2] = 3;&#13;
dynamVec.push_back(6);&#13;
printMe(dynamVec);&#13;
&#13;
// Constant range of constant elements&#13;
const std::vector<int> constVec = origVec; // (2)&#13;
// constVec[2] = 3; ERROR&#13;
// constVec.push_back(6); ERROR&#13;
std::span<const int> constSpan(origVec); // (3)&#13;
// constSpan[2] = 3; ERROR&#13;
&#13;
// Constant range of modifiable elements&#13;
std::span<int> dynamSpan{origVec}; // (4)&#13;
dynamSpan[2] = 3;&#13;
printMe(dynamSpan);&#13;
&#13;
std::cout << 'n';&#13;
&#13;
}


vektör dynamVec (1) değişen unsurlarla değişen bir alandır. Bu beyan taşıyıcı için geçerli değildir constVec (2). constVec öğelerini veya boyutunu değiştiremez. constSpan (3) buna göre davranın. dynamSpan (4) değiştirilebilir öğelerle sabit bir bölgenin benzersiz kullanım durumunu modeller.

Son olarak, kullanırken iki tehlikeye dikkat çekmek istiyorum. std::span Bilmen gerekir.

Std::span'ın tehlikeleri


Tipik sorunları std::span ikisi farklı şeylerdir. Öncelikle şunları yapmalısınız: std::span geçici bir alana uygulanmamalıdır; ikincisi, alttaki bitişik alanın boyutu bir olmalıdır std::span değiştirilmemelidir.

A std::span geçici bir alanda


A std::span hiçbir zaman tescilli değildir ve altındaki alanın ömrünü uzatmaz. Bu nedenle yapmalısınız std::span yalnızca lValues üzerinde çalışır. Birinin kullanımı std::span geçici bir alanda tanımlanmamış bir davranıştır.


// temporarySpan.cpp&#13;
&#13;
#include <iostream>&#13;
#include <span>&#13;
#include <vector>&#13;
&#13;
std::vector<int> getVector() { // (2)&#13;
return {1, 2, 3, 4, 5};&#13;
}&#13;
&#13;
int main() {&#13;
&#13;
std::cout << 'n';&#13;
&#13;
std::vector<int> myVec{1, 2, 3, 4, 5}; // (1)&#13;
std::span<int, 5> mySpan1{myVec}; &#13;
std::span<int, 5> mySpan2{getVector().begin(), 5}; // (3)&#13;
&#13;
for (auto v: std::span{myVec}) std::cout << v << " ";&#13;
std::cout << 'n';&#13;
for (auto v: std::span{getVector().begin(), 5}) std::cout << v << " "; // (4)&#13;
&#13;
std::cout << "nn";&#13;
&#13;
}


Birinin kullanımı std::span statik uzantılı oa std::span lValue'da dinamik bir uzantıya sahip olmak gayet iyi. Eğer lValue verirsem std::vector (1)'de geçici olana std::vector fonksiyon aracılığıyla değiştirin getVector (2) oluşturulduğunda, programın tanımsız davranışı vardır. Hem (3) hem de (4) geçersizdir. Yürütüldükten sonra tanımsız davranış görünür hale gelir. (4)'teki çıktı bununla aynı fikirde değil std::vector fonksiyonunkiyle eşleş getVector() üretilmektedir.

Temel bitişik bölgenin boyutunu değiştirme

Temeldeki bitişik alanın boyutunun değiştirilmesi, bitişik alanın yeniden tahsisine ve std::span geçerliliğini yitirmiş verileri ifade eder.


std::vector<int> myVec{1, 2, 3, 4, 5};&#13;
&#13;
std::span<int> sp1{myVec};&#13;
&#13;
myVec.push_back(6); // undefined behavior


Sıradaki ne?


Bir sonraki yazımda C++20 biçimlendirme kitaplığına tekrar dalacağım.

ALS araştırması için bağış toplama kampanyamız









My Modern C++ Collection 3 kitaplık paketi artık yarı fiyatına (70 $ -> 35 $) satılıyor. Parayı ALS araştırmalarına bağışlayacağım. Gerçeklerle başlayayım.

ALS araştırması ciddi şekilde yetersiz finanse ediliyor


İşte ALS kliniğinden yapılan açıklama:

ALS tıbbın “sorunlu çocuklarından” biridir: Nadir hastalıklar toplumsal ilginin merkezinde değildir. ALS araştırması için genel bir finansman yoktur. Sonuç olarak, ALS'li kişilerin tedavisine önemli ölçüde finansman sağlanamıyor. Burada bağışlar ve dış destekler çok önemli.

Bu yetersiz finansman Buz Kovası Mücadelesi ile vurgulandı.

Araştırmanın daha fazla paraya ihtiyacı var. İşte benim fikrim: Bir bağış toplama etkinliği başlatalım!

Bağış toplama kampanyamız


Yarı fiyatlı Modern C++ Koleksiyonu 3 Kitaplık Paket kuponu (70 $ -> 35 $) 21 Ocak (dahil) tarihine kadar geçerlidir.

Bu pakete aşağıdaki üç kitap dahildir: The C++ Standard Library, Concurrency with Modern C++ ve C++20.

Paranın tamamını ALS kliniğine bağışlayacağım. ALS kliniği Charité'nin bir parçasıdır ve Avrupa'da ALS araştırma ve tedavisinde liderdir.


(kendim)



Haberin Sonu
 
Üst