Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compacting bools feature of std::vector in C++

Does the std::vector in C++ compact bools? I mean I have read that std::vector can combine 8 booleans into 1 byte. However, when I tried this code in visual studio,

#include <vector>
#include <iostream>
using namespace std;

int main()
{
    vector<bool> array {true, false, false, true, true,false,false,true};
    cout << sizeof(array) << endl;
    cout << sizeof(array[0]) << endl;

    getchar();
    return 0;
}

it printed:

24
16

while in another IDE, such as codeblocks, it printed 20 and 8.

I don't quite get what it does with booleans here.

like image 566
W.Joe Avatar asked Apr 25 '18 03:04

W.Joe


2 Answers

Does the std::vector in C++ compact bools?

Yes, it is allowed to do so, and typically does.

I don't quite get what it does with booleans here.

You actually don't get what array[0] evaluates to.

It does not evaluate to a bit. It evaluates to a proxy object that correctly handles both conversion to bool and assignment from bool.

the sizeof this proxy does not have much significance. It is not the size of a bit or a bool. It's the size of an object programmed to act on a specific bit.

like image 117
Drew Dormann Avatar answered Oct 05 '22 23:10

Drew Dormann


std::vector usually uses dynamic allocation internally by default. If you define your own allocator that tracks actual allocation size, you'll see that the number of bytes allocated for vector<bool> implies values are stored as bits:

#include <vector>
#include <iostream>

template<typename T>
class my_allocator : public std::allocator<T> {
public:
    T * allocate(const size_t count) {
        std::cout << "Allocated " << count << " * " << typeid(T).name() << std::endl;
        std::cout << "Total size: " << count * sizeof(T) << std::endl;
        return std::allocator<T>::allocate(count);
    }

    T * allocate(const size_t count, const void *) {
        return allocate(count);
    }

    template<typename U>
    struct rebind {
        typedef my_allocator<U> other;
    };

    my_allocator() noexcept {};
    my_allocator(const my_allocator<T>&) noexcept = default;

    template<typename Other>
    my_allocator(const my_allocator<Other>&) noexcept {}
};

int main() {
    std::vector<int, my_allocator<int>> v1 { 0 };
    std::vector<bool, my_allocator<bool>> v2 { 0 };

    v1.reserve(100);
    v2.reserve(100);

    return 0;
}

Relevant output:

Allocated 100 * int
Total size: 400
Allocated 4 * unsigned int
Total size: 16

Demo: https://wandbox.org/permlink/WHTD0k3sMvd3E4ag

like image 21
Vladislav Ivanov Avatar answered Oct 06 '22 01:10

Vladislav Ivanov