Передача std :: vector <bool>внешней функции - PullRequest
2 голосов
/ 06 мая 2019

Я имею дело с библиотекой, в которой я не могу изменить типы данных. Мне нужно вызвать функцию, которая принимает массив bool. Код, с которым я работаю, использует std::vector<bool> для хранения bools. Я много читал о std::vector<bool> и связанных с этим проблемах на SO, но я не нашел наиболее элегантного решения для моей проблемы. Это код, где производительность имеет решающее значение. Как мне решить эту проблему наиболее эффективным способом? Я могу изменить тип, хранящийся в std::vector, но не могу избежать использования std::vector.

В моей собственной проблеме я должен вызывать функции Фортрана, но я сделал минимальный пример на C ++, который иллюстрирует проблему.

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

Ответы [ 3 ]

5 голосов
/ 06 мая 2019

Вы знаете, что нужно сделать ... Создайте временный массив bools и скопируйте значения.

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;

или

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());
2 голосов
/ 06 мая 2019

Я могу изменить тип, хранящийся в std::vector, но не могу выйти от использования std::vector.

В этом случае вам не повезло. std::vector<bool> не хранит массив логических значений, а также data() не возвращает указатель на массив логических значений (как и все остальные std::vectors для их соответствующих типов данных).

Вы можете сыграть несколько трюков и использовать std::vector<uint8_t> или аналогичный, хотя, даже если размер совпадает, uint8_t* не является bool*! Учитывая, что функция не может измениться, вы можете избежать строгого наложения псевдонимов, только скопировав данные в массив bool.

Если вам небезразлична производительность, я бы посоветовал не использовать std::vector<bool>. Например, вам действительно нужен динамический размер? Если не использовать std::array.

0 голосов
/ 06 мая 2019

Я попытался заставить его работать на вашем примере, и следующее (довольно грязное) решение работало нормально:

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

Вывод, который я получил:

0: правда
1: ложно
2: ложно
3: правда
4: ложно

0: правда
1: ложно
2: ложно
3: правда
4: ложно

Однако я не знаю, будет ли он вести себя одинаково на каждой системе / платформе. Но если вы не собираетесь менять свою систему / платформу, и если она действительно работает на вашей, я думаю, что она могла бы сделать эту работу, даже если это довольно грязное решение.

На самом деле, если мы можем гарантировать, что sizeof(bool) == sizeof(uint8_t) и при условии, что true и false соответственно обрабатываются в памяти как целые числа 1 и 0, это решение будет работать, но не иначе.

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ: заменены uint8_t на char тип.


EDIT2:

Другое решение, которое не нарушает правило строгого наложения имен, - это то, о котором Камил Цук упомянул, - создание оболочки Bool и проверка того, что sizeof(bool) == sizeof(Bool).

Возможная реализация (только базовый код) может быть:

struct Bool
{
    bool v;

    Bool(bool bv=false) : v(bv)
    {}
};

И тогда вы сможете написать:

std::vector<Bool> b_vec {true, false, false, true, false};
test_print(reinterpret_cast<bool*>(b_vec.data()), b_vec.size());

у меня сработало:)

...