【发布时间】:2019-07-17 02:52:25
【问题描述】:
我想将包含多个整数的结构的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>>?
【问题讨论】:
-
如果你必须这样做,你可以转换
std::vector::data()的结果来获得指向向量管理的第一个元素的指针。 -
这是未定义的行为。不保证便携,不保证工作。
-
您可以将向量返回的 data() 指针重新解释转换为另一种类型,但不能将整个向量转换为另一种类型。即使您仅 reinterpet_cast 数据指针,它也只有在 pragma pack 设置为 1 时才可移植,否则 sizeof(struct Tuple) 可能大于 3 * sizeof(int)。
-
不要这样做。如果您是初学者,您不应该使用
reinterpret_cast<>。这段代码只是被破坏了,它工作的事实只是一个随机的幸运机会。更改任何内容(包括编译器标志)都可能导致它崩溃。 -
你问它是如何知道它是 15 而不是 5。虽然代码是无效的,正如其他地方所涵盖的那样,但那个特定的位可能很有趣。向量不存储大小,它存储指向数据开始和结束的指针,大小返回,本质上是 end() - begin()。如果您想了解它最终如何工作godbolt.org/z/B1Uvq4 - 更改指针转换为的类型或结构中缓冲区的大小,它可能会变得更容易看到。
标签: c++ vector std allocator reinterpret-cast