Libc ++ 'nın <bool> :: const_reference vektörü neden bool değil?


92

Bölüm 23.3.7 Sınıf vector<bool>[vector.bool], paragraf 1 şunu belirtir:

template <class Allocator> class vector<bool, Allocator> {
public:
    // types:
    typedef bool              const_reference;
    ...

Ancak bu program libc ++ kullanırken derleme yapamaz:

#include <vector>
#include <type_traits>

int
main()
{
    static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}

Ayrıca, C ++ standardının bu spesifikasyonda C ++ 98'e kadar tutarlı olduğunu not ediyorum. Ayrıca libc ++ 'nın, libc ++' nın ilk tanıtımından bu yana sürekli olarak bu belirtime uymadığını not ediyorum.

Bu uyumsuzluğun nedeni nedir?

Yanıtlar:


99

Uygun bir program tarafından tespit edilebilen ve dolayısıyla uygun olmayan bu uzantının motivasyonu, referanslara göre (const ve diğer) vector<bool>daha çok davranmaktır vector<char>.

Giriş

1998'den vector<bool>beri "pek kapsayıcı değil" diye alay ediliyor. İlk LWG sorunlarından biri olan LWG 96 , tartışmayı başlattı. Bugün, 17 yıl sonra, vector<bool>büyük ölçüde değişmeden kalır.

Bu makale , davranışının vector<bool>diğer tüm somutlaştırmalardan nasıl farklılaştığına ve vectorböylece genel koda zarar verdiğine dair bazı özel örneklere giriyor . Bununla birlikte, aynı makale, vector<bool>düzgün bir şekilde uygulandığında çok güzel performans özelliklerinin sahip olabileceği uzun uzadıya tartışılmaktadır .

Özet : vector<bool>kötü bir kap değil. Aslında oldukça kullanışlıdır. Sadece kötü bir adı var.

Geri dön const_reference

Yukarıda açıklandığı ve burada ayrıntılı olarak açıklandığı gibi, kötü olan şey vector<bool>, genel kodda diğer vectorörneklerden farklı şekilde davranmasıdır . İşte somut bir örnek:

#include <cassert>
#include <vector>

template <class T>
void
test(std::vector<T>& v)
{
    using const_ref = typename std::vector<T>::const_reference;
    const std::vector<T>& cv = v;
    const_ref cr = cv[0];
    assert(cr == cv[0]);
    v[0] = 1;
    assert(true == cv[0]);
    assert(cr == cv[0]);  // Fires!
}

int
main()
{
    std::vector<char> vc(1);
    test(vc);
    std::vector<bool> vb(1);
    test(vb);
}

Standart belirtim, işaretlenen iddianın // Fires!tetikleneceğini, ancak yalnızca testbir vector<bool>. Bir ile çalıştırıldığında vector<char>(veya herhangi bir vectoryanında bool, uygun bir varsayılan olmayan zaman Tatanır), test başarılı olur.

Libc ++ uygulaması vector<bool>, genel kodda farklı davranmanın olumsuz etkilerini en aza indirmeye çalıştı . Bunu başarmak için yaptığı bir şey , tıpkı belirtilen gibi vector<T>::const_referencebir vekil referansı yapmaktır vector<T>::reference, ancak bunun dışında atayamazsınız. Yani, libc ++ 'da vector<T>::const_reference, aslında vectoro bitin bir kopyası yerine içindeki biti gösteren bir göstericidir .

Libc ++ 'da yukarıdakiler testhem vector<char>ve hem de vector<bool>.

Ne pahasına?

Olumsuz yanı, soruda gösterildiği gibi bu uzantının algılanabilir olmasıdır. Ancak, çok az program aslında bu takma adın tam türünü önemsemekte ve daha fazla program davranışı önemsemektedir.

Bu uyumsuzluğun nedeni nedir?

Libc ++ istemcisine genel kodda daha iyi davranış sağlamak için ve belki de yeterli alan testinden sonra, bu uzantıyı tüm C ++ endüstrisinin iyileştirilmesi için gelecekteki bir C ++ standardına önerin.

Böyle bir öneri bit_vector, bugünkü API ile hemen hemen aynı API'ye vector<bool>sahip, ancak const_referenceburada tartışılanlar gibi birkaç yükseltmeye sahip yeni bir kapsayıcı (örneğin ) biçiminde gelebilir . Ardından vector<bool>uzmanlığın kullanımdan kaldırılması (ve sonunda kaldırılması) . bitsetayrıca bu bölümde biraz yükseltme, örneğin ekleme const_referenceve bir dizi yineleyici kullanabilir.

Gez içinde bir deyişle, bitsetetmektir vector<bool>(hangi adlandırılması bit_vectorgibi - ya da her neyse) arrayetmektir vector. Ve benzetme bahsediyoruz olsun veya olmasın doğru çıkması gerektiğini boololarak value_typebir vectorve array.

Libc ++ 'da uzantılar olarak başlayan C ++ 11 ve C ++ 14 özelliklerinin birçok örneği vardır. Standartlar bu şekilde gelişir. Gerçek olarak gösterilen pozitif saha deneyimi, güçlü bir etkiye sahiptir. Standartlar, mevcut spesifikasyonları (olması gerektiği gibi) değiştirmek söz konusu olduğunda muhafazakar bir gruptur. Doğru tahmin ettiğinizden emin olsanız bile tahmin etmek, uluslararası kabul görmüş bir standardı geliştirmek için riskli bir stratejidir.


1
Soru: @EricNiebler tarafından vekil yineleyicilerle ilgili son taslak öneri libc ++ uzantılarını bir şekilde meşrulaştırabilir ve vector<bool>daha birinci sınıf bir temel oluşturabilir mi?
TemplateRex

Remark: Bir olmasını tercih ediyorum vector_bool<Alloc>ve bir array_bool<N>arasında (rastgele erişimli vekil tüm bitleri yineleme Yineleyicilerin dahil) paketlenmiş versiyonlarını temsil etmek vector<bool, Alloc>ve array<bool, N>. Ancak, bitset<N>(ve onun kuzeni boost::dynamic_bitset<Alloc>) farklı bir soyutlamayı temsil eder: yani std::set<int>. Ben söylüyorlar, istiyorum Yani bit_array<N>ve bit_vector<Alloc>uygun olan bitset franchise için ardılları, olmak iki yönlü iterators (yerine tüm bitler üzerinde 1-bit yineleme). Bu konudaki düşüncelerin neler?
TemplateRex

5
Proxy yineleyicilerle ilgili taslak önerim, vector<bool>standartlara uygun rasgele erişimli bir kapsayıcı yapacak . Bu yapmazdım vector<bool>iyi bir fikir. :-) Howard'a katılıyorum. Başka bir şey olarak adlandırılmalıydı.
Eric Niebler

1
Neden libc ++ uzantılarını devre dışı bırakmanın ve kesinlikle uyumlu davranışlar edinmenin bir yolu yok? (Uyumluluğu varsayılan hale getirmeyi bile istemiyorum, sadece libc ++ 'nın uzantılarını taşınabilir kod yazabilmek için devre dışı bırakmanın bir yolu). Bildiğiniz gibi geçmişte libc ++ tuple uzantıları tarafından ısırıldım ve son zamanlarda bitset :: const_reference uzantısı tarafından ısırıldım.
gnzlbg

5
@gnzlbg: libc ++ 'nın ilk geliştirilmesi için sınırlı miktarda ekonomik ve zamansal kaynak mevcuttu. Daha sonra uygulama, her kullanıcıyı mutlu etmemeye mahkum edildi. Mevcut kaynaklar göz önüne alındığında, mutlu kullanıcıların sayısını en üst düzeye çıkarmak, genel C ++ topluluğuna yararı en üst düzeye çıkarmak amacıyla mühendislik değiş tokuşları yapıldı. Deneyiminiz için üzgünüm. Karşılaştığınız tuple uzantılarının şu an mevcut C ++ 1z çalışma kağıdında olduğunu not ediyorum. Bu konuda, farkında olmadan birçoğunun yararlanabilmesi için fedakarlık yaptınız ve çoğu kişi size minnettarlık borçlu.
Howard Hinnant
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.