参与 std::vector C++
Posted
技术标签:
【中文标题】参与 std::vector C++【英文标题】:Taking part of std::vector C++ 【发布时间】:2017-05-28 20:29:24 【问题描述】:在我的代码中我有这样的东西:
struct SomeStruct
int test1;
int test2;
float test3;
float test4;
;
std::vector<SomeStruct> SomeStructs;
我正在寻找一种方法以连续方式获取该向量的一部分,以便我可以使用指针或 c 数组访问它。
假设我想要一个指针来仅访问结构的 test2 部分。 我想将向量的那部分传递给 C API,可以吗?
我试图避免创建一个新的 std::vector/c-array。
它在记忆中的样子(有点):
【问题讨论】:
没有语言“C/C++”,向量是一个纯粹的 C++ 结构,所以请从标题和标签中删除 C。您能否提供有关您的意思的更多信息:我想要一个仅访问该列的指针。你能指定指针的用途吗?授予某些用户访问权限,传递给 C API... “我正在寻找一种方法以连续方式获取该向量的一部分,以便我可以使用指针或 c 数组访问它。”抱歉,这是不可能的;vector<SomeStruct>
在内存中布置为一系列相邻的 SomeStruct
实例,因此 test2
列的每个元素相隔 sizeof(SomeStruct)
字节,而不是像在int[]
。因此,除非您将该数据复制出来,否则您不能拥有指向“仅该列”的指针并将其用作指向 int
s 的常规数组中元素的指针。
更改您的 C++ 代码以使用数组结构 (SoA) 而不是结构数组 (AoS)。也就是说,每列一个向量。将其包装在一个带有重载运算符的类中,以方便 C++ API。将 std::vector::data()
传递给 C API。
@Drop 我会试试的。谢谢!
【参考方案1】:
不,你所要求的是不可能的。快速回顾:
-
我们可以清楚地看到该结构的 test2 条目当前并未在内存中连续布置,因为它们只是连续结构的一个成员,因此其他结构元素显然位于每个 test2 出现之间。
您希望它们是连续的,因此您需要与当前不同的内存布局。
您不想创建新的向量或数组,因此您会卡在当前的内存布局中,这是错误的。
你的选择是这样的:
-
将变量更改为 4 个变量向量,而不是 1 个结构向量。
在需要时创建一个新向量。
不要使用需要连续内存的 C API。
值得注意的是,一些 C API,尤其是 BLAS,支持“跨步”数组,这意味着元素之间存在固定的大小差距,这将为您解决这个问题。
【讨论】:
【参考方案2】:无法从指针或数组中仅访问每个test2
的内容,因为即使向量中的结构是,test2
成员在内存中也不连续。结构中还有其他数据,因此您需要跳过它来读取每个test2
。
当您发现自己提出这样的问题时,请尝试考虑您可以使用的其他数据结构,以使问题更容易解决。对于这种情况,std::unordered_map
可能是一个不错的选择。
std::unordered_map<int,SomeStruct> map;
// make a struct...
map.insert(std::make_pair<int,SomeStruct>(a_struct.test2,a_struct));
// add a bunch more structs...
// get an iterator to all the keys in the map (ie. something like a pointer to all test2 members)
key_iterator = map.begin()
【讨论】:
【参考方案3】:要以惯用的方式实现这一点,您需要滚动您自己的自定义 iterator
,它专门返回该字段。
看看c++ how to create iterator over one field of a struct vector
C 和 C++ 互操作性是一个截然不同的问题。为了简化事情,您可能只想在 C 中实现它。
【讨论】:
【参考方案4】:如果我得到你的好,我认为这是可能的。
struct SomeStruct
int test1;
int test2;
float test3;
float test4;
;
int size = 3;// whatever size
vector<SomeStruct> myStruct(size);
myStruct[0].test1 = 0;
myStruct[1].test1 = 1;
myStruct[2].test1 = 2;
/* myPtest1 will allow you to get the test1 part of myStruct in a
contiguous memory manner*/
int *myPtest1 = new int(myStruct.size());
for(int i = 0; i< myStruct.size(); i++)
myPtest1[i] = myStruct[i].test1;
// for illustration.
cout << myPtest1[0] << endl; // 0
cout << myPtest1[1] << endl; // 1
cout << myPtest1[2] << endl; // 2
您现在可以将myPointer
传递给您的API,myPointer 只允许您访问myStruct
向量的test1
部分。
您可以对其余的 SomeStruct
属性执行相同操作。
【讨论】:
@JohnMiz 如果我能把你弄好,我认为这是可能的【参考方案5】:如果你想在 for 循环中访问它,你可以这样做:
for (const auto& iterator: SomeStructs)
const int& test2 = iterator.test2;
// do what you need to do
如果你需要第 j 个元素:
const int& test2 = SomeStructs[j].test2
通过这种方式,您不会制作额外的副本,而是直接引用 vector 中的项目。如果需要更改值,请删除 const
【讨论】:
以上是关于参与 std::vector C++的主要内容,如果未能解决你的问题,请参考以下文章
在 C++ std::vector 和 C 数组之间转换而不复制
为啥在 C++11 中更改了 std::vector::resize 签名?
如何在 C++17 中将 std::string 转换为 std::vector<std::byte>?