C ++ 20'deki aralık aralığı: Daha ileri tasarım kararları
Performansların yararına C ++ 20'de aralık aralığının bazı özel özellikleri vardır. Bu tasarım kararlarının sonuçları vardır: önbellek ve tutarlılık ile ilgili sorunlar.
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.
İşte kısa bir bellek. Son makalemde “C ++ 20: Kararların Tasarımı” std::ranges::filter_view Sunulan:
if constexpr (!ranges::forward_range<V>)
return /* iterator */{*this, ranges::find_if(base_, std::ref(*pred_))};
else
{
if (!begin_.has_value())
begin_ = ranges::find_if(base_, std::ref(*pred_)); // caching
return /* iterator */{*this, begin_.value())};
}
En önemli gözlem, begin-sonraki çağrılar için kriterci arşivlenir. Bu ara mevduatın iki ilginç sonucu var:
Daha önemli tasarım kararları var.
Tutarlılık
Bir görünümün üye işlevi pozisyonu kaydedebilir. Bu aşağıdaki noktaları ima eder:
Evrensel referans yoluyla herhangi bir görünüm alın
İşlev printElements Evrensel referans için fikrinizi kabul edin.
void printElements(std::ranges::input_range auto&& rang) {
for (int i: rang) {
std::cout << i << " ";
}
std::cout << 'n';
}
printElements Argümanınızı evrensel bir referansla kabul edin. Bunları lValue'ye referans olarak kabul edin veya bir değerin olumsuz sonuçları vardır.
Lvale'e sürekli referans konusu önemli değil çünkü örtük begin-Chiamare görüş konuyu değiştirebilir. Aksine, uygun olmayan bir lvalue referansı bir rvalue ayrıntılı olarak açıklayamaz.
Ancak, konuyu bir değer olarak kabul etmek ara belleği geçersiz kılabilir.
Aynı zamanda, görünümleri okumak bir veritabanı olabilir
Aşağıdaki program, görüşlere rekabet sorununu göstermektedir:
// dataRaceRanges.cpp
#include <numeric>
#include <iostream>
#include <ranges>
#include <thread>
#include <vector>
int main() {
std::vector<int> vec(1'000);
std::iota(vec.begin(), vec.end(), 0);
auto first5Vector = vec | std::views::filter([](auto v) { return v > 0; })
| std::views::take(5);
std::jthread thr1([&first5Vector]{
for (int i: first5Vector) {
std::cout << i << " ";
}
});
for (int i: first5Vector) {
std::cout << i << " ";
}
std::cout << "nn";
}
Programdayım dataRaceRanges.cpp İki kez değiştirmeden aynı anda bir görünüm. İlk ITI std::jthread thr1 Ve sonra main-İşlev. Bu bir veri ihalesidir çünkü her iki yineleme de dolaylı olarak üyenin işlevi begin Pozisyonu kurtarabilecek ABD. Throlanitizer bu veri yarışını görünür hale getirir ve 24. satırdaki önceki bir mektuptan şikayet eder: std::cout << i << " ";
Aksine, yineleme gibi klasik bir kaptan std::vector Güvenli tartışma. Klasik kaplar ve görüşler arasında başka bir fark daha var.
Konstanzın yayılması
Klasik kaplar orta derin tutarlılık. Onları unsurlarına iletirler. Bu, sabit bir kabın elemanlarını değiştirmenin imkansız olduğu anlamına gelir.
// constPropagationContainer.cpp
#include <iostream>
#include <vector>
template <typename T>
void modifyConstRange(const T& cont) {
cont[0] = 5;
}
int main() {
std::vector myVec{1, 2, 3, 4, 5};
modifyConstRange(myVec); // ERROR
}
Arama modifyConstRange(myVec)derleme süresi boyunca hataya neden olur.
Aksine, görüşler düz bir kıvam oluşturur. Bunları unsurlarına iletmeyin. Bu nedenle öğeler hala değiştirilebilir.
// constPropagationViews.cpp
#include <iostream>
#include <ranges>
#include <vector>
template <typename T>
void modifyConstRange(const T& cont) {
cont[0] = 5;
}
int main() {
std::vector myVec{1, 2, 3, 4, 5};
modifyConstRange(std::views::all(myVec)); // OK
}
Arama modifyConstRange(std::views::all(myVec)) Önemli değil.
Sırada ne var?
Koro muhtemelen C ++ 20'nin en zorlu bileşenidir. Bir sonraki makalem Dian-Lun Lin'in konukları için bir yazı. Koroya kısa bir giriş yapacak ve fikrini görevleri yöneten basit bir programa dayanarak gösterecek.
(RME)
C ++ 20'deki aralık aralığı: Daha ileri tasarım kararları
Performansların yararına C ++ 20'de aralık aralığının bazı özel özellikleri vardır. Bu tasarım kararlarının sonuçları vardır: önbellek ve tutarlılık ile ilgili sorunlar.

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.

İşte kısa bir bellek. Son makalemde “C ++ 20: Kararların Tasarımı” std::ranges::filter_view Sunulan:
if constexpr (!ranges::forward_range<V>)
return /* iterator */{*this, ranges::find_if(base_, std::ref(*pred_))};
else
{
if (!begin_.has_value())
begin_ = ranges::find_if(base_, std::ref(*pred_)); // caching
return /* iterator */{*this, begin_.value())};
}
En önemli gözlem, begin-sonraki çağrılar için kriterci arşivlenir. Bu ara mevduatın iki ilginç sonucu var:
- Değiştirilen alanlarda bir görünüm kullanılmamalı
- Bir görünümü kopyalayamazsınız.
Daha önemli tasarım kararları var.
Tutarlılık
Bir görünümün üye işlevi pozisyonu kaydedebilir. Bu aşağıdaki noktaları ima eder:
- Herhangi bir vizyonu yapan bir işlev, evrensel referans e ile almalıdır
- İki görünümün eşzamanlı okunması bir veritabanına yol açabilir.
Evrensel referans yoluyla herhangi bir görünüm alın
İşlev printElements Evrensel referans için fikrinizi kabul edin.
void printElements(std::ranges::input_range auto&& rang) {
for (int i: rang) {
std::cout << i << " ";
}
std::cout << 'n';
}
printElements Argümanınızı evrensel bir referansla kabul edin. Bunları lValue'ye referans olarak kabul edin veya bir değerin olumsuz sonuçları vardır.
Lvale'e sürekli referans konusu önemli değil çünkü örtük begin-Chiamare görüş konuyu değiştirebilir. Aksine, uygun olmayan bir lvalue referansı bir rvalue ayrıntılı olarak açıklayamaz.
Ancak, konuyu bir değer olarak kabul etmek ara belleği geçersiz kılabilir.
Aynı zamanda, görünümleri okumak bir veritabanı olabilir
Aşağıdaki program, görüşlere rekabet sorununu göstermektedir:
// dataRaceRanges.cpp
#include <numeric>
#include <iostream>
#include <ranges>
#include <thread>
#include <vector>
int main() {
std::vector<int> vec(1'000);
std::iota(vec.begin(), vec.end(), 0);
auto first5Vector = vec | std::views::filter([](auto v) { return v > 0; })
| std::views::take(5);
std::jthread thr1([&first5Vector]{
for (int i: first5Vector) {
std::cout << i << " ";
}
});
for (int i: first5Vector) {
std::cout << i << " ";
}
std::cout << "nn";
}
Programdayım dataRaceRanges.cpp İki kez değiştirmeden aynı anda bir görünüm. İlk ITI std::jthread thr1 Ve sonra main-İşlev. Bu bir veri ihalesidir çünkü her iki yineleme de dolaylı olarak üyenin işlevi begin Pozisyonu kurtarabilecek ABD. Throlanitizer bu veri yarışını görünür hale getirir ve 24. satırdaki önceki bir mektuptan şikayet eder: std::cout << i << " ";

Aksine, yineleme gibi klasik bir kaptan std::vector Güvenli tartışma. Klasik kaplar ve görüşler arasında başka bir fark daha var.
Konstanzın yayılması
Klasik kaplar orta derin tutarlılık. Onları unsurlarına iletirler. Bu, sabit bir kabın elemanlarını değiştirmenin imkansız olduğu anlamına gelir.
// constPropagationContainer.cpp
#include <iostream>
#include <vector>
template <typename T>
void modifyConstRange(const T& cont) {
cont[0] = 5;
}
int main() {
std::vector myVec{1, 2, 3, 4, 5};
modifyConstRange(myVec); // ERROR
}
Arama modifyConstRange(myVec)derleme süresi boyunca hataya neden olur.
Aksine, görüşler düz bir kıvam oluşturur. Bunları unsurlarına iletmeyin. Bu nedenle öğeler hala değiştirilebilir.
// constPropagationViews.cpp
#include <iostream>
#include <ranges>
#include <vector>
template <typename T>
void modifyConstRange(const T& cont) {
cont[0] = 5;
}
int main() {
std::vector myVec{1, 2, 3, 4, 5};
modifyConstRange(std::views::all(myVec)); // OK
}
Arama modifyConstRange(std::views::all(myVec)) Önemli değil.
Sırada ne var?
Koro muhtemelen C ++ 20'nin en zorlu bileşenidir. Bir sonraki makalem Dian-Lun Lin'in konukları için bir yazı. Koroya kısa bir giriş yapacak ve fikrini görevleri yöneten basit bir programa dayanarak gösterecek.
(RME)