std::vector和C风格数组

10

我正在尝试使用OpenCL来提高软件的运行速度。我们经常处理地图,为了简化表示,将地图表示为一个std::vector< std::vector >。在上面的例子中,OpenCL API需要原始的c风格指针作为参数,例如int*。

我的问题:

  • STL中有实现保证vector在内部是连续存储的吗?
  • 我能安全地将std::vector 强制转换为int*并期望它能正常工作吗?
  • 对于一个向量的向量,我仍然可以假设这是真的吗?我预计vector会持有其他状态数据、对齐问题或其他一些问题...
  • 最好的方法是什么?编写一个自定义的2D数据结构来持有内部的连续存储缓冲区,并使用它?我必须经常从vector复制/到vector复制...

谢谢。


您可能也对这个问题感兴趣:https://dev59.com/nXM_5IYBdhLWcg3wiDqA - P Shved
1
请注意,vector<bool>是规则的例外。http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=98 - Motti
4个回答

18

STL中的vector是否有实现保证其在内部是连续的内存?

从C++03开始,是的,vector保证使用连续的内存。(在C++98中,存在一个意外的漏洞,因此实现可以使用非连续的存储,但它在标准的2003修订版中得到了修复 - 也没有实现实际上使用非连续的存储,因为这将是个可怕的想法)

我能安全地将std::vector转换为int*并期望它能正常工作吗?

通常的方法是&v[0]。(&*v.begin()可能也可以工作,但我似乎记得标准中有一些模糊的措辞,使这不是100%可靠的)

不行。您为什么会期望这样做呢?vector是一个类。它不是指针。它只是包含一个指针。

对于嵌套vector的情况,我仍然可以假设这是真的吗?我希望vector保存其他状态数据,或对齐问题,或者可能是其他什么...

无论您存储什么,vector的行为都是相同的。如果您创建一个向量的向量,您最终会得到一个包含指向堆分配数组的指针的对象,在该数组中,每个元素都是包含指向堆分配数组的指针的对象。

至于如何处理这个问题,这取决于许多因素。您的总数据集有多大?您可能希望整个表分配连续空间。使用vector的向量,每一行都是单独的分配。


谢谢。实际上我表达不当,我是指“将第一个元素转换为指针”,而不是“转换向量本身”或“向量本身的地址”。无论如何,似乎没有简单地使用向量向量的原始内容的方法,我必须重新思考数据处理方式。典型的大小在500x500xsizeof(unsigned char)和2500x2500xsizeof(double)之间,然后有20到50个,因此非常大。 - Roel
Boost.MultiArray可以很好地为您完成此任务。或者,我会分配一个足够大以容纳整个二维表的单个连续数组或向量。 - jalf
1
请注意,vector<bool>是一个例外情况,即&v[0]不会给出一个C风格的数组。 - Motti
&*v.begin() 只有在数组非空的情况下才能使用。(解引用 end() 是未定义行为,在许多平台上会在调试构建中给出断言) - pgast
@pgast:对于 &v[0] 也是如此。 - jalf

5
  • STL中的vector在内部是否是连续存储的?

是的,它是动态数组。标准保证vector内部存储的对象是连续的。

  • 我能否安全地将std::vector转换为int*并期望它能正常工作?

不行,但是你可以使用begin()函数并将其用作指针。

  • STL中的vector在内部是否是连续存储的?

不是的,因为vector可能包含一些内部成员变量,整个二维数组将不是连续的内存位置。


1
不,但你可以使用begin()并将其用作指针。这通常不是真的,并且绝对不能由标准保证。您应该始终获取解引用迭代器的地址以获取指针,因此"&*v.begin()"而不是仅使用"v.begin()"。 - Pieter

4

STL中的vector是否保证内部连续存储?

虽然我不能在这里引用标准,但我已经在高质量的库中看到了假设这种布局(即POCO)的代码。

我可以安全地将std::vector强制转换为int*,并期望它可以工作吗?

具体来说,您不能重新转换向量本身。但是,我曾看到过以下代码:

std::vector<int> vec;
int* ptr = &vec[0];

对于一个向量的向量,这个规律仍然适用吗?我会预期这个向量会存储其他状态数据、对齐问题或者其他一些东西...

你可能无法将一个向量的向量转换为线性数组。每个向量都将保留自己的内存范围,不能期望所有这些范围是连续的。


@jalf:谢谢,你说得对。我把&vec[0]和(int*)vec.begin()搞混了。 - Ferdinand Beyer

3

您在评论中提到您使用高达2500x2500xsizeof(double)的数据。在这种情况下,我建议使用一个单一的向量而不是向量的向量。在向量中分配NxM元素,并将其包装在一个类中,以便暴露二维索引。您可以获得向量的所有好处,同时最小化开销,并且所有数据仍然位于连续内存中,以便快速处理。


是的,在这个问题的背景下,这可能是我/我们应该采取的方法。问题在于我们的“地图”数据类型也需要能够从不同的位置读取(通过网络,在磁盘上读取那些太大而无法放入内存的地图(20 GB的地图也不例外)...)。我们只需要测试几种方法,或者实现几种方法,并具有运行时选择器机制,以确定用户机器/问题集上的最佳行为。无论如何,感谢您的评论。 - Roel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接