reinterpret_cast 如何展平 std::vector?
How reinterpret_cast works for flattening a std::vector?
我想将包含多个整数的结构的 std::vector
表示为 "flatten" 整数向量, 无需复制数据。
我尝试了一些带有 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
? (如果我 "accidentally" 添加一个 double
成员到 Tuple
,由此产生的问题可能很难追踪...)
- 如果
vec1
有一个特定的分配器:std::vector<Tuple,A<Tuple>>
,vec2
的类型应该是什么? std::vector<int>
或 std::vector<int,A<int>>
或 std::vector<int,A<Tuple>>
?
您不能合法地将整个向量 reinterpret_cast 转换为不同类型的向量。但是您可以合法地将指向结构的指针转换为指向该结构的第一个元素的指针。所以这有效:
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*
.
我想将包含多个整数的结构的 std::vector
表示为 "flatten" 整数向量, 无需复制数据。
我尝试了一些带有 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
? (如果我 "accidentally" 添加一个double
成员到Tuple
,由此产生的问题可能很难追踪...) - 如果
vec1
有一个特定的分配器:std::vector<Tuple,A<Tuple>>
,vec2
的类型应该是什么?std::vector<int>
或std::vector<int,A<int>>
或std::vector<int,A<Tuple>>
?
您不能合法地将整个向量 reinterpret_cast 转换为不同类型的向量。但是您可以合法地将指向结构的指针转换为指向该结构的第一个元素的指针。所以这有效:
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*
.
- 同上,