Reputation: 6194
I am dealing with a library of which I cannot change the data types. I need to call a function that takes a bool
array. The code that I am working with uses std::vector<bool>
to store the bools. I have read a lot about std::vector<bool>
and the associated problems on SO, but I have not found the most elegant solution for my problem. This is a code where performance is crucial. How do I deal with this problem in the most efficient way? I can change the type stored in the std::vector
, but I cannot escape from using std::vector
.
In my own problem, I have to call Fortran functions, but I have made a minimal example in C++ that illustrates the problem.
#include <cstdio>
#include <vector>
void print_c_bool(bool* bool_array, size_t n)
{
for (int i=0; i<n; ++i)
printf("%d, %d\n", i, bool_array[i]);
}
int main()
{
// This works.
bool bool_array[5] = {true, false, false, true, false};
print_c_bool(bool_array, 5);
// This is impossible, but how to solve it?
std::vector<bool> bool_vector {true, false, false, true, false};
// print_c_bool(bool_vector.data(), bool_vector.size());
return 0;
}
Upvotes: 2
Views: 770
Reputation: 6805
I tried to make it work using your example and the following (quite dirty) solution worked fine:
#include <iostream>
#include <vector>
void test_print(bool * arr, size_t s)
{
for(unsigned int i = 0; i< s; ++i)
std::cout << i << ": " << (arr[i]?"true\n":"false\n");
std::cout << std::endl;
}
int main()
{
bool b_arr[5] = {true, false, false, true, false};
test_print(b_arr, 5);
//std::vector <uint8_t> b_vec = {true, false, false, true, false}; // former proposal
std::vector <char> b_vec = {true, false, false, true, false}; // new proposal
test_print(reinterpret_cast<bool*>(b_vec.data()), b_vec.size());
return 0;
}
The output I got is:
0: true
1: false
2: false
3: true
4: false
0: true
1: false
2: false
3: true
4: false
However, I don't know if it will behave the same on every system/platform. But if you don't intend to change your system/platform and if it does work on yours, I think it could do the job even if it is a quite dirty solution.
In fact, if we can guarantee that sizeof(bool) == sizeof(uint8_t)
and assuming that true
and false
are respectively treated in memory as integers 1
and 0
, this solution will work, but not otherwise.
I hope it can help.
EDIT: Replaced uint8_t
by char
type.
EDIT2:
Another solution that does not violate the strict aliasing rule is the one that Kamil Cuk mentioned that is to create a Bool wrapper and still check that sizeof(bool) == sizeof(Bool)
.
A possible implementation (just the baseline code) can be:
struct Bool
{
bool v;
Bool(bool bv=false) : v(bv)
{}
};
And then you will be able to write:
std::vector<Bool> b_vec {true, false, false, true, false};
test_print(reinterpret_cast<bool*>(b_vec.data()), b_vec.size());
It worked for me :)
Upvotes: 0
Reputation: 122133
I can change the type stored in the
std::vector
, but I cannot escape from usingstd::vector
.
In this case you are out of luck. std::vector<bool>
does not store an array of booleans, neither does its data()
return a pointer to an array of booleans (as all other std::vectors
do for their respective data type).
You can play some tricks and use std::vector<uint8_t>
or similar, though even if the size matches, a uint8_t*
is not a bool*
! Given that the function cannot change, you can only avoid to violate strict aliasing by copying the data into a bool array.
If you do care about performance, then I'd suggest to consider not using std::vector<bool>
. For example, do you really need dynamic size? If not use a std::array
.
Upvotes: 2
Reputation: 140880
You know what you have to do... Create a temporary array of bools and copy the values.
auto v = new bool[bool_vector.size()];
std::copy(bool_vector.begin(), bool_vector.end(), v);
print_c_bool(v, bool_vector.size());
delete[] v;
or
auto v = std::make_unique<bool>(bool_vector.size());
std::copy(bool_vector.begin(), bool_vector.end(), v.get());
print_c_bool(v.get(), bool_vector.size());
Upvotes: 5