12

What's the best way to store a bit array in C++ (no Boost, just standard containers), representing, for example, a volume allocation bitmap?

I thought std::vector<bool> was a great idea, but apparently it's Evil and deprecated, so is there a better choice?

Also:

If I have a byte array in memory, how would I go about copying them to the recommended container?
(I'm having trouble figuring this out for vector<bool>.)

Community
  • 1
  • 1
user541686
  • 205,094
  • 128
  • 528
  • 886
  • 1
    The article you linked to recommends `std::dynamic_bitset`... – Greg Hewgill Oct 20 '11 at 00:41
  • @GregHewgill: That doesn't seem to be in standard C++...? Or am I just not finding it? – user541686 Oct 20 '11 at 00:44
  • It's not that evil if you don't need flip() or other special behavior. :P – shinkou Oct 20 '11 at 00:53
  • 1
    `dynamic_bitset` [is in Boost](http://www.boost.org/doc/libs/1_36_0/libs/dynamic_bitset/dynamic_bitset.html). – Mikhail Glushenkov Oct 20 '11 at 00:53
  • 6
    There's nothing wrong with `vector`, unless you expect it to behave like a standard container. – Mark Ransom Oct 20 '11 at 00:53
  • @MarkRansom: I see, thanks for the comment. If I were to use `vector`, then, how should I copy to it the data from a byte array? (I had trouble figuring this out -- doing it bool-by-bool is very slow because of locking issues, so I'm hoping for a bulk operation.) – user541686 Oct 20 '11 at 00:56
  • dynamic_bitset is part of the boost library: http://www.boost.org/doc/libs/1_47_0/libs/dynamic_bitset/dynamic_bitset.html – Serdalis Oct 20 '11 at 00:56
  • @MikhailGlushenkov: I guess that's definitely a valid answer, although I probably won't switch to C++11 just to use this container. :) (I already mentioned I don't want Boost.) Thanks for the comment though! – user541686 Oct 20 '11 at 00:58
  • @Mehrdad I double-checked, and it looks like it's not in C++11 after all. Maybe it will be in TR2. – Mikhail Glushenkov Oct 20 '11 at 01:00
  • @MarkRansom "_There's nothing wrong with vector, unless you expect it to behave like a standard container._" IOW, there is nothing wrong unless you understand C++ and also expect the C++ standard to be written by people who understand C++. – curiousguy Oct 20 '11 at 01:06
  • Obviously my previous comment was meant to be a little tongue-in-cheek. It will efficiently hold a large quantity of `bool`, but there are many ways in which it breaks expectations. For one, you cannot take the address of the first element and have a contiguous array of bool, as you can with every other vector. And even though you know the internal representation is an array of bytes, there's no way to access it. P.S. if you ever really need a vector of boolean values that acts like a true vector, use `vector` and be aware that it will use 8 times memory of a more optimized solution. – Mark Ransom Oct 20 '11 at 03:14
  • As others have suggested, `dynamic_bitset` from Boost seems like a good candidate. But since you don't want Boost, can't you just get that small part from Boost, or copy just that part to a separate library? – Some programmer dude Oct 21 '11 at 14:36
  • I answered your "Also" in my answer. – Gnawme Oct 21 '11 at 22:13
  • To everyone who thinks this is a duplicate of the other question: unlike that one, this one is looking for a **dynamic** bitset **without** Boost. Please don't randomly close a 6-year-old question for no good reason. – user541686 May 16 '17 at 10:19

6 Answers6

2

Just posting this 6 years later for posterity: like one of the commenters said, I came to the conclusion that it's perfectly fine to use std::vector<bool> as its own specialized type. The only thing you need to be careful of is not to treat it like a standard bool container, since it isn't.

user541686
  • 205,094
  • 128
  • 528
  • 886
2

a char array and then masking by 0x1 will act as a bit array.

Example:

char bitarray[4]; // since 4*8 this array actually contains 32 bits

char getBit(int index) {
    return (bitarray[index/8] >> 7-(index & 0x7)) & 0x1;
}

void setBit(int index, int value) {
    bitarray[index/8] = bitarray[index/8] | (value & 0x1) << 7-(index & 0x7);
}

of course these operations are usually comparatively slow, but if memory is an issue this is a decent way to go. I chose char's for this to reduce the number of shifts needed. However it may still be faster with integers.

Yetti99
  • 326
  • 2
  • 11
Serdalis
  • 10,296
  • 2
  • 38
  • 58
  • Sure, I could implement it myself, but how is that beneficial to using `vector`? – user541686 Oct 20 '11 at 00:48
  • 1
    you quoted a perfect example of why you should not use `vector`, this does not suffer from its downfall and if you wish you can also address your array in 4 bit chunks, which can be handy in some situations. I am not a C/C++ guru but this just seems more correct, since bool was a hack in C anyway. – Serdalis Oct 20 '11 at 00:54
  • yeah, wow, how did I mess that up, thanks for pointing that out. *fixes* – Serdalis Oct 20 '11 at 01:12
  • Actually you should use `CHAR_BIT` or something like that instead of assuming that the byte size is 8 bit. – Matteo Italia Oct 21 '11 at 22:19
  • @Matteo true, however this is more a general how to and I wouldn't be able to use `0x7`, I'd probably need a class that can determine which hex to use and work from there. Unless someone can convert `CHAR_BIT` to `0xCHAR_BIT-1` easily. – Serdalis Oct 22 '11 at 00:58
  • @Serdalis: It'd be `(CHAR_BIT-1)`. But you could no longer use bitwise AND as a faster modulo. Using only 8 bits per byte is fine, any wasted space will be more than compensated for by the increased speed. – Ben Voigt Oct 22 '11 at 01:20
  • 1
    It would be difficult to justify doing anything more than: `#if (CHAR_BIT != 8) #error`. – Don Reba Oct 22 '11 at 01:30
2

The std::bitset will do, as long as your bit array is of fixed size.
As a side note there's also std::dynamic_bitset, but am not 100% sure it made it into the standard.

Eugen Constantin Dinca
  • 8,994
  • 2
  • 34
  • 51
2

For vanilla C++, there's std::bitset.

Bitset is very similar to vector (also known as bit_vector): it contains a collection of bits, and provides constant-time access to each bit. There are two main differences between bitset and vector. First, the size of a bitset cannot be changed: bitset's template parameter N, which specifies the number of bits in the bitset, must be an integer constant. Second, bitset is not a Sequence; in fact, it is not an STL Container at all.

Matt Austern has a nice article on its use.

Also: If your byte array (bit array?) fits into an unsigned long, then you can assign it to a std::bitset directly:

unsigned long myByteArray = 0xABCD;
std::bitset<32> bitten( myByteArray );
Gnawme
  • 2,321
  • 1
  • 15
  • 21
0

Powerful C/С++ bit array library: https://github.com/noporpoise/BitArray

Dennis V
  • 574
  • 7
  • 19
0

I think some of the points made on the site you linked to are not correct by the way. On almost every computer the size of a bit is really one byte (same as a character) because computers can only address a byte not a bit within a byte (if you could then you would only have one eighth of the addressing space you currently have with bytes)

I would just use a byte for your vector because it gives other people who read your code a better idea of the memory footprint of your application.

Ram is very plentiful in modern computers so you may be able to use larger integral types but realistically you can't go smaller than a byte.

To copy data from one container to another first create an iterator for the container

vector::iterator myItr = myVector.begin()

and iterate through the vector with a while loop or a for loop until myItr reaches myVector.end().

For example

for(vector<bool>::iterator myItr = myVector.begin(); myItr<myVector.end(); ++myItr)
{
   otherContainer.append(*myItr);
}
bashirs
  • 452
  • 1
  • 7
  • 14
  • The trouble with copying data like that^ is that it's painfully slow. Not just because it's bit-by-bit, but because implementations (e.g. Visual C++) sometimes arbitrarily decide to lock a critical section on every single access, so it becomes ridiculously impractical. I was looking for a bulk movement operation (something like `items.assign(myArray, numBits)`, which would turn out to be more practical, but I couldn't find it. – user541686 Oct 20 '11 at 00:47
  • 2
    "_the size of a bit _" Hug? What do you mean? – curiousguy Oct 20 '11 at 00:50