<bool> vektörüne alternatif


92

Hepimizin bildiği gibi (umarım) vector<bool>, tamamen bozuktur ve bir C dizisi olarak ele alınamaz. Bu işlevi almanın en iyi yolu nedir? Şimdiye kadar düşündüğüm fikirler:

  • vector<char>Bunun yerine a kullanın veya
  • Bir sarmalayıcı sınıfı kullanın ve vector<bool_wrapper>

Siz bu sorunu nasıl çözüyorsunuz? c_array()İşlevselliğe ihtiyacım var .

Bir yan soru olarak, c_array()yönteme ihtiyacım yoksa , rastgele erişime ihtiyacım varsa bu soruna yaklaşmanın en iyi yolu nedir? Süs veya başka bir şey kullanmalı mıyım?

Düzenle:

  • Dinamik boyutlandırmaya ihtiyacım var.
  • Bilmiyorum olanlar için, vector<bool>her şekilde uzmanlaşmıştır bool1 bit alır. Dolayısıyla, onu C tarzı bir diziye dönüştüremezsiniz.
  • Sanırım "sarmalayıcı" biraz yanlış bir isim. Bunun gibi bir şey düşünüyordum:

Elbette, my_boololası hizalama sorunları nedeniyle aşağıdakileri okumam gerekiyor :(

struct my_bool
{
    bool the_bool;
};
vector<my_bool> haha_i_tricked_you;

2
C-tarzı bir dizi kullanmamak için bir sebep var mı?
kquinn

rlbond, dinamik boyuta ihtiyacınız var mı?
Johannes Schaub - litb

16
Tamam ısıracağım - neden vektörün "" tamamen bozuk "olduğunu düşünüyorsun?
Andrew Grant


4
İlginç bir şekilde, vector<bool>kodumda bir veri yarışı hatasına neden oldu, çünkü farklı iş parçacıklarının vektördeki farklı öğeleri aynı anda güvenli bir şekilde değiştirmesini bekledim. Kullanılarak çözüldü deque<bool>.
Andres Riofrio

Yanıtlar:



21

Bu ilginç bir problem.

Eğer uzmanlaşmamış olsaydı std :: vector ne olurdu ihtiyacınız varsa, o zaman belki bunun gibi bir şey sizin durumunuzda iyi sonuç verir:

#include <vector>
#include <iostream> 
#include <algorithm>

class Bool
{
public:

    Bool(): m_value(){}
    Bool( bool value ) : m_value(value){}

    operator bool() const { return m_value; }

    // the following operators are to allow bool* b = &v[0]; (v is a vector here).
    bool* operator& () { return &m_value; }
    const bool* operator& () const { return &m_value; }

private:

    bool m_value;

};




int main()
{
    std::vector<Bool> working_solution(10, false);


    working_solution[5] = true;
    working_solution[7] = true;


    for( int i = 0; i < working_solution.size(); ++i )
    {
        std::cout<< "Id " << i << " = " << working_solution[i] << "(" <<(working_solution[i] ? "true" : "false") << ")" <<std::endl; // i used ? : to be sure the boolean evaluation is correct
    }

    std::sort( working_solution.begin(), working_solution.end());
    std::cout<< "--- SORTED! ---" << std::endl;

    for( int i = 0; i < working_solution.size(); ++i )
    {
            bool* b = &working_solution[i]; // this works!

        std::cout<< "Id " << i << " = " << working_solution[i] << "(" << (working_solution[i] ? "true" : "false") << ")" <<std::endl; // i used ? : to be sure the boolean evaluation is correct
    }

    std::cin.get();
    return 0;
}

Bunu VC9 ile denedim ve iyi çalışıyor gibi görünüyor. Bool sınıfının amacı, aynı davranışı ve boyutu (ancak aynı türü değil) sağlayarak bool türünü simüle etmektir. Neredeyse tüm iş burada bool operatörü ve varsayılan kopya oluşturucuları tarafından yapılır. Algoritmaları kullanırken varsayıldığı gibi tepki verdiğinden emin olmak için bir sıralama ekledim.

Her duruma uygun olduğundan emin değilim. İhtiyaçlarınız için doğruysa, vektör benzeri bir sınıfı yeniden yazmaktan daha az iş olur ...


"bool * operatörü ekleyebiliriz & () {dönüş & m_value;}" - hata. ISO : " sizeof(bool)olması gerekli değildir 1"
Evgeny Panasyuk

2
Basitçe operator bool() constbir operator bool&(). Bu, basit bir bool davranışını daha iyi yansıtmasını sağlar, çünkü v[0] = true;bu değişiklikle ilgili bir sorunu gerçekten göremediğim durumlarda, atama vb. Durumlarda , düzenlemeyi yapabilir miyim?
Agentlien

19

İhtiyaçlarınıza bağlıdır. Ben de giderdim std::vector<unsigned char>. Bir sarmalayıcı yazmak, işlevin yalnızca bir alt kümesini kullanırsanız iyi olabilir, aksi takdirde bir kabusa dönüşür.


unsigned charher zaman tek bayttır, uint8_tancak uygulama tarafından desteklenmeyebilir. uint_fast8_tniyet o tek bayt değil, bir karakter temizlemek yapmaktır eğer olsa işe yarayabilir ancak siz de kullanabilir std::bytesonra
Gabriel Ravier

13

Siz bu sorunu nasıl çözüyorsunuz? C_array () işlevselliğine ihtiyacım var.

boost::container::vector<bool>:

vektör < bool > uzmanlığı oldukça sorunlu olmuştur ve onu standarttan kaldırmak veya kaldırmak için birkaç başarısız girişim olmuştur. Boost.Containerüstün bir Boost.DynamicBitset çözümü olduğu için bunu uygulamaz .

...

Yani boost :: container :: vector :: iterator , gerçek bool referansları döndürür ve tamamen uyumlu bir kap olarak çalışır. Boost :: container :: vector < bool > işlevlerinin bellek için optimize edilmiş bir sürümüne ihtiyacınız varsa , lütfen Boost.DynamicBitset'i kullanın .


6

<İnt> vektörünü kullanmayı düşünün. Derlemeyi ve yazım denetimini geçtikten sonra, bool ve int sadece makine sözcükleridir (düzenleme: görünüşe göre bu her zaman doğru değildir; ancak birçok PC mimarisinde doğru olacaktır). Uyarı olmadan dönüştürmek istediğiniz durumlarda, sıfırı yanlışa ve sıfır olmayanı doğruya dönüştüren "bool foo = !! bar" kullanın.

<Char> vektörü veya benzeri bir vektör daha az alan kullanır, ancak bazı durumlarda (çok küçük) bir hız vuruşu alma potansiyeline sahiptir, çünkü karakterler makinenin kelime boyutundan daha küçüktür. Bool'ların karakter yerine ints kullanılarak uygulanmasının ana nedeninin bu olduğuna inanıyorum.

Gerçekten temiz anlambilim istiyorsanız, kendi boole sınıfınızı oluşturma önerisini de seviyorum - bir bool gibi görünüyor, bir bool gibi davranıyor, ancak şablon uzmanlığını kandırıyor.

Ayrıca, <bool> vektörünün C ++ standardından çıkarılmasını isteyen insanlar kulübüne hoş geldiniz (bunun yerine bit_vector ile). Bütün havalı çocukların takıldığı yer :).


4

Bu sorun zaten edildi tartışılan ++ comp.lang.c üzerinde. Yönetilir. Önerilen çözümler:

  • kendi ayırıcınız (dayalı std::allocator) ve kendi vektör uzmanlığınız;
  • kullanımı std::deque(S. Mayers kitaplarından birinde önerildiği gibi) - ancak bu sizin ihtiyaçlarınız için değil;
  • POD boolsarıcı yapmak ;
  • bunun yerine aynı boyutta bir şey ( char/ int/ vb) boolkullanın bool;

Ayrıca erken dönemde standart komite önerisini gördüm - STD_VECTOR_BOOL_SPECIALbu uzmanlığa izin vermemek için makro (benzeri bir şey ) tanıtın - ancak AFAIK bu öneri stl uygulamalarında uygulanmadı ve onaylanmadı.

Görünüşe göre probleminizin bunu güzelce yapmanın bir yolu yok ... Belki C ++ 0x'de.


3

En basit cevap, vector<struct sb>nerede sbolduğunu kullanmaktır struct {boolean b};. O zaman söyleyebilirsin push_back({true}). İyi görünüyor.


2

Benim tercih ettiğim geçici çözüm, vectortemelde bir tür olan kapsamlı bir numaralandırmadır bool. Bu vector<bool>, komite uzmanlaşmamış olsaydı sahip olacağımız duruma oldukça yaklaşıyor .

enum class switch_status : bool { ON, OFF };

static_assert( sizeof( switch_status ) == 1 );

::std::vector<switch_status> switches( 20, switch_status::ON );

static_assert( ::std::is_same_v< decltype( switches.front() ), switch_status &> );
static_assert( ::std::is_same_v< decltype( switches.back()  ), switch_status &> );
static_assert( ::std::is_same_v< decltype( switches[ 0 ]    ), switch_status &> );

Aşağıdakilere / şuradan alçıları kucaklamanın hikmeti hakkında kendi fikirleriniz olacak bool:

enum class switch_status : bool { OFF = false, ON = true };

static_assert( static_cast< bool          >( switch_status::ON  ) == true               );
static_assert( static_cast< bool          >( switch_status::OFF ) == false              );
static_assert( static_cast< switch_status >( true               ) == switch_status::ON  );
static_assert( static_cast< switch_status >( false              ) == switch_status::OFF );
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.