Alternative to vector

2019-01-01 09:35发布

问题:

As (hopefully) we all know, vector<bool> is totally broken and can\'t be treated as a c array. What is the best way to get this functionality? So far, the ideas I have thought of are:

  • Use a vector<char> instead, or
  • Use a wrapper class and have vector<bool_wrapper>

How do you guys handle this problem? I need the c_array() functionality.

As a side question, if I don\'t need the c_array() method, what is the best way to approach this problem if I need random access? Should I use a deque or something else?

Edit:

  • I do need dynamic sizing.
  • For those who don\'t know, vector<bool> is specialized so that each bool takes 1 bit. Thus you can\'t convert it to a c-style array.
  • I guess \"wrapper\" is a bit of a misnomer. I was thinking something like this:

Of course, then I have to read into a my_bool due to possible alignment issues :(

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

回答1:

Use std::deque if you don\'t need the array, yes.

Otherwise use an alternative vector that doesn\'t specialize on bool, such as the one in Boost Container.



回答2:

That\'s an interesting problem.

If you need what would have been a std::vector if it was not specialized, then maybe something like that would work fine with your case :

#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 * const 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;
}

I tried this with VC9 and it seems to work fine. The idea of the Bool class is to simulate the bool type by providing the same behavior and size (but not the same type). Almost all the work is done by the bool operator and the default copy constructors here. I added a sort to be sure it react as assumed when using algorithms.

Not sure it would suit all cases. If it\'s right for your needs, it would be less work than rewriting a vector-like class...



回答3:

Depends on your needs. I would go for either std::vector<unsigned char>. Writting a wrapper can be fine if you only use a subset of the functionality, else it will become a nightmare.



回答4:

How do you guys handle this problem? I need the c_array() functionality.

boost::container::vector<bool>:

vector<bool> specialization has been quite problematic, and there have been several unsuccessful tries to deprecate or remove it from the standard. Boost.Container does not implement it as there is a superior Boost.DynamicBitset solution.

...

So boost::container::vector::iterator returns real bool references and works as a fully compliant container. If you need a memory optimized version of boost::container::vector<bool> functionalities, please use Boost.DynamicBitset.



回答5:

Consider using a vector< int >. Once you get past compilation and type checking, bool and int are both just machine words (edit: apparently this is not always true; but will be true on many PC architectures). In those cases where you want to convert without a warning, use \"bool foo = !!bar\", which converts zero to false and non-zero to true.

A vector< char > or similar will use less space, though it also has the potential to take a (very small) speed hit in some circumstances, because characters are less than the machine word size. This is, I believe, the main reason that bools are implemented using ints instead of chars.

If you really want clean semantics, I also like the suggestion of making your own boolean class -- looks like a bool, acts like a bool, but fools the template specialization.

Also, welcome to the club of people who want the vector< bool > specialization dropped from the C++ standard (with bit_vector to replace it). It\'s where all the cool kids hang out :).



回答6:

Simplest answer is use vector<struct sb> where sb is struct {boolean b};. Then you can say push_back({true}). It seems good.



回答7:

This problem was already discussed on comp.lang.c++.moderated. Proposed solutions:

  • your own allocator (based on std::allocator) and own vector specialization;
  • use std::deque (as early was recommended in one of books S. Mayers) - but this not for your requirements;
  • make POD bool wrapper;
  • use something (char/int/etc) with same size as bool instead bool;

Also early I saw proposal for standard committee - introduce macro (something like STD_VECTOR_BOOL_SPECIAL) to disallow this specialization - but AFAIK this proposal was not implemented in stl implementations and wasn\'t approved.

It seems that your problem has no ways to do this nicely... Maybe in C++0x.



回答8:

My preferred workaround is a vector of a scoped enum that has an underlying type of bool. This gets pretty close to the vector<bool> we would have had if the committee hadn\'t specialised it.

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 &> );

You will have your own opinions about the wisdom of embracing casts to/from 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 );