参与 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&lt;SomeStruct&gt; 在内存中布置为一系列相邻的 SomeStruct 实例,因此 test2 列的每个元素相隔 sizeof(SomeStruct) 字节,而不是像在int[]。因此,除非您将该数据复制出来,否则您不能拥有指向“仅该列”的指针并将其用作指向 ints 的常规数组中元素的指针。 更改您的 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++11 时的 std::vector 性能回归

如何在 C++17 中将 std::string 转换为 std::vector<std::byte>?

c ++:选择一个std :: vector的子集,基于预定义的元素索引

为啥 C++11 会从 std::vector 填充构造函数的原型中移除默认值?