COW basic_string
, C ++ 11 ve sonrasında yasaklanmış mıdır ?
ilişkin
” C ++ 11'in COW tabanlı uygulamalarını kabul etmediğini doğru muyum std::string
?
Evet.
ilişkin
” Eğer öyleyse, bu kısıtlama yeni standartta (nerede) açıkça belirtilmiş mi?
Neredeyse doğrudan,bir COW uygulamasında dizi verilerininO ( n ) fiziksel olarak kopyalanmasınıgerektiren bir dizi işlem için sürekli karmaşıklık gereksinimleri nedeniyle.
Örneğin, üye işlevleri için
auto operator[](size_type pos) const -> const_reference;
auto operator[](size_type pos) -> reference;
… Bir COW uygulamasında, her ikisi de dize değerini paylaşmamak için dize verilerinin kopyalanmasını tetikler, C ++ 11 standardı
C ++ 11 §21.4.5 / 4 :
" Karmaşıklık: sabit zaman.
… Bu tür veri kopyalamayı ve dolayısıyla COW'u dışlayan.
C ++ 03 tarafından İNEK uygulamaları desteklenen değil bu sabit karmaşıklık gereksinimlerini sahip ve belirli kısıtlayıcı koşullar altında, tarafından çağrıları izin operator[]()
, at()
, begin()
, rbegin()
, end()
, veya rend()
, yani dize öğelere atıfta invalidate referanslar, işaretçiler ve yineleyiciler için muhtemelen tabi a COW verileri kopyalanıyor. Bu destek C ++ 11'de kaldırılmıştır.
COW, C ++ 11 geçersiz kılma kuralları aracılığıyla da yasaklanmış mı?
Yazılırken çözüm olarak seçilen ve büyük ölçüde olumlu oy alan ve bu nedenle görünüşe göre inanılan başka bir cevapta,
” Bir COW dizisi için, non const
operator[]
- çağrılması, bir kopya oluşturmayı (ve referansları geçersiz kılma) gerektirir; bu, yukarıdaki [C ++ 11 §21.4.1 / 6] paragrafında izin verilmeyen [alıntı]. Bu nedenle, C ++ 11'de bir COW dizesine sahip olmak artık yasal değildir.
Bu iddia iki ana yönden yanlış ve yanıltıcıdır:
- Yanlış bir şekilde, yalnızca
const
öğe olmayan erişimcilerin bir COW veri kopyalamayı tetiklemesi gerektiğini belirtir .
Ancak, const
öğe erişimcilerinin de veri kopyalamayı tetiklemesi gerekir, çünkü istemci kodunun (C ++ 11'de) COW veri kopyalamayı tetikleyebilecek işlemler yoluyla daha sonra geçersiz kılmalarına izin verilmeyen referanslar veya işaretçiler oluşturmasına izin verirler.
- Yanlış bir şekilde COW veri kopyalamanın referansın geçersiz kılınmasına neden olabileceğini varsayar.
Ancak doğru bir uygulamada, COW veri kopyalama, dize değerinin paylaşılmasının kaldırılması, geçersiz kılınabilecek herhangi bir referansın olmadığı bir noktada yapılır.
Doğru bir C ++ 11 COW uygulamasının basic_string
nasıl çalışacağını görmek için, bunu geçersiz kılan O (1) gereksinimleri göz ardı edildiğinde, bir dizenin sahiplik ilkeleri arasında geçiş yapabileceği bir uygulama düşünün. Bir dize örneği, Politika Paylaşılabilir ile başlar. Bu politika etkinken harici öğe referansı olamaz. Örnek Benzersiz ilkeye geçiş yapabilir ve bir çağrıda olduğu gibi potansiyel olarak bir öğe başvurusu oluşturulduğunda .c_str()
(en azından bu dahili arabelleğe bir işaretçi üretiyorsa) bunu yapması gerekir. Değerin sahipliğini paylaşan birden çok örnek olması durumunda, bu, dize verilerinin kopyalanmasını gerektirir. Bu Benzersiz politikaya geçişten sonra örnek, yalnızca atama gibi tüm referansları geçersiz kılan bir işlemle Paylaşılabilir'e geri dönebilir.
Dolayısıyla, cevabın COW dizgilerinin dışlandığı sonucu doğru olsa da, sunulan mantık yanlış ve kesinlikle yanıltıcıdır.
Bu yanlış anlaşılmanın nedeninin C ++ 11'in ek C'deki normatif olmayan bir not olduğundan şüpheleniyorum:
C ++ 11 §C.2.11 [diff.cpp03.strings], yaklaşık §21.3:
Değişiklik : basic_string
gereksinimler artık referans sayılan dizelere izin vermiyor.
Gerekçe: Geçersiz kılma, referans sayılan dizelerle biraz farklıdır. Bu değişiklik, bu Uluslararası Standart için davranışı (sic) düzenler.
Orijinal özellik üzerindeki etki: Geçerli C ++ 2003 kodu, bu Uluslararası Standartta farklı şekilde yürütülebilir
Buradaki mantık , C ++ 03 özel COW desteğini neden kaldırmaya karar verdiğinizi açıklıyor . Bu gerekçe, nedeni , standardın COW uygulamasına nasıl etkin bir şekilde izin vermediği değildir . Standart, O (1) gereksinimleri aracılığıyla COW'a izin vermez.
Kısacası, C ++ 11 geçersiz kılma kuralları COW uygulamasının std::basic_string
. Ancak, g ++ 'nın standart kütüphane uygulamalarından en az birinde olduğu gibi, makul derecede verimli, kısıtlanmamış C ++ 03 tarzı bir COW uygulamasını ekarte ederler. Özel C ++ 03 COW desteği const
, geçersiz kılma için ince, karmaşık kurallar pahasına, özellikle öğe erişimcileri kullanarak pratik verimliliğe izin verdi :
"İlk çağrı" COW desteğini içeren
C ++ 03 §21.3 / 5 :
” Bir basic_string
dizinin öğelerine atıfta bulunan referanslar, işaretçiler ve yineleyiciler , bu basic_string
nesnenin aşağıdaki kullanımları ile geçersiz kılınabilir :
- Üye olmayan işlevlere bir argüman olarak swap()
(21.3.7.8), operator>>()
(21.3.7.9) ve getline()
(21.3. 7.9).
- Bir argüman olarak basic_string::swap()
.
- Arama data()
ve c_str()
üye fonksiyonları.
- olmayan çağrılması const
dışında, üye işlevlerini operator[]()
, at()
, begin()
, rbegin()
, end()
, ve rend()
.
- formları dışında Yukarıdaki kullanımların herhangi biri için sonraki insert()
ve erase()
yineleyici dönüş olmayan ilk çağrı const
elemanı fonksiyonları operator[]()
, at()
, begin()
, rbegin()
,end()
, veya rend()
.
Bu kurallar o kadar karmaşık ve incelikli ki, varsa birçok programcının kesin bir özet verebileceğinden şüpheliyim. Yapamadım.
O (1) gereksinimleri göz ardı edilirse ne olur?
Örneğin, C ++ 11 sabit zaman gereksinimleri operator[]
göz ardı edilirse, COW for basic_string
teknik olarak uygulanabilir, ancak uygulaması zor olabilir.
COW veri kopyalamasına maruz kalmadan bir dizinin içeriğine erişebilen işlemler şunları içerir:
- Üzerinden birleştirme
+
.
- Üzerinden çıktı
<<
.
basic_string
Standart kütüphane işlevlerine bağımsız değişken olarak kullanmak .
İkincisi, standart kitaplığın uygulamaya özel bilgi ve yapılara dayanmasına izin verildiği için.
Ek olarak bir uygulama, COW veri kopyalamayı tetiklemeden dizi içeriklerine erişmek için çeşitli standart dışı işlevler sunabilir.
Bir ana komplike faktör 11 C ++ olmasıdır basic_string
öğe erişim zorunluluk tetik veri kopyalama (string verileri un paylaşımı) fakat için gereklidir atmak değil mesela C ++ 11 §21.4.5 / 3, “ atar: . Hiçbir şey”. Ve bu nedenle, COW veri kopyalama için yeni bir arabellek oluşturmak için sıradan dinamik ayırmayı kullanamaz. Bunu aşmanın bir yolu, belleğin gerçekte tahsis edilmeden rezerve edilebildiği özel bir yığın kullanmak ve ardından bir dize değerine her mantıksal referans için gerekli miktarı ayırmaktır. Böyle bir yığında ayırma ve ayırma işlemi sabit zaman olabilir, O (1) ve birinin önceden ayırmış olduğu miktarı tahsis etmek,noexcept
. Standardın gerekliliklerine uymak için, bu yaklaşımla, her ayrı ayırıcı için böyle bir özel rezervasyon tabanlı yığın olması gerekeceği görülmektedir.
Notlar:
¹ const
Öğe erişimcisi, istemci kodunun verilere bir referans veya işaretçi almasına izin verdiği için bir COW verisi kopyalamayı tetikler; bu, örneğin const
öğe olmayan erişimci tarafından tetiklenen daha sonraki bir veri kopyalama ile geçersiz kılınmasına izin verilmez .