Как reinterpret_cast работает для выравнивания std :: vector? - PullRequest
0 голосов
/ 23 февраля 2019

Я хотел бы представить std::vector структуры, содержащей несколько целых чисел, в виде "сплющенного" вектора целых чисел, без копирования данных .

Я пробовал что-то с reinterpret_cast, как показано ниже:

#include <vector>
#include <iostream>

struct Tuple
{
    int a, b, c;
};

int main()
{
    // init
    std::vector<Tuple> vec1(5);
    for(size_t i=0; i<vec1.size(); ++i)
    {
        vec1[i].a = 3 * i + 0;
        vec1[i].b = 3 * i + 1;
        vec1[i].c = 3 * i + 2;
    }   

    // flattening
    std::vector<int>* vec2 = reinterpret_cast<std::vector<int>*>(&vec1);

    // print
    std::cout << "vec1 (" << vec1.size() << ")  : ";
    for(size_t i=0; i<vec1.size(); ++i)
    {
        std::cout << vec1.at(i).a << " " << vec1.at(i).b << " " << vec1.at(i).c << " ";
    }
    std::cout << std::endl;

    std::cout << "vec2 (" << vec2->size() << ") : ";
    for (size_t j = 0; j < vec2->size(); ++j)
    {
        std::cout << vec2->at(j) << " ";
    }
    std::cout << std::endl;

    return 0;
}

, который хорошо работает, так как вывод:

vec1 (5)  : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 
vec2 (15) : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 

Мои вопросы:

  • Зависит ли это поведение от компилятора?(Я использую g++ 6.3.0)
  • Как vec2 знает, что размер вектора равен 15, а не 5?
  • Есть ли какое-либо другое решение, позволяющее избежать использованияreinterpret_cast?(Если я «случайно» добавлю double член к Tuple, возникшую проблему будет трудно отследить ...)
  • Если vec1 имеет определенный распределитель:std::vector<Tuple,A<Tuple>>, какой должен быть тип vec2?std::vector<int> или std::vector<int,A<int>> или std::vector<int,A<Tuple>>?

1 Ответ

0 голосов
/ 23 февраля 2019

Вы не можете юридически повторно интерпретировать весь вектор для другого типа вектора.Но вы можете легально привести указатель на структуру к указателю на первый элемент этой структуры.Так что это работает:

std::vector<Tuple> vec1(5);
int* vec2 = &vec1.front().a;
size_t vec2_size = vec1.size() * sizeof(vec1[0]) / sizeof(vec2[0]);

for (size_t j = 0; j < vec2_size; ++j)
{
    std::cout << vec2[j] << " ";
}

Вы должны убедиться, что в Tuple нет заполнения, поэтому:

static_assert(sizeof(Tuple) == 3 * sizeof(int), "Tuple must be 3 ints");

Чтобы ответить на ваши маркированные вопросы:

  • Зависит ли это поведение от компилятора?
    • Ваш код был недопустим.
  • Как vec2 узнает, что размер вектора равен 15, а не 5?
    • Вам повезло, ваш код был недопустим.
  • Есть ли какое-либо другое решение, позволяющее избежать использования reinterpret_cast?
    • См. Выше.
  • Если у vec1 есть определенный распределитель: std :: vector>, каким должен быть тип vec2?
    • То же, что и выше, int*.
...