将嵌套的C++向量作为内置样式的多维数组传递

Pass nested C++ vector as built-in style multi-dimensional array

本文关键字:数组 样式 C++ 嵌套 向量 内置      更新时间:2023-10-16

如果我在C++中有一个向量,我知道我可以安全地将其作为数组(指向所包含类型的指针(传递:

void some_function(size_t size, int array[])
{
    // impl here...
}
// ...
std::vector<int> test;
some_function(test.size(), &test[0]);

使用嵌套向量这样做安全吗?

void some_function(size_t x, size_t y, size_t z, int* multi_dimensional_array)
{
    // impl here...
}
// ...
std::vector<std::vector<std::vector<int> > > test;
// initialize with non-jagged dimensions, ensure they're not empty, then...
some_function(test.size(), test[0].size(), test[0][0].size(), &test[0][0][0]);

编辑:

如果它不安全,有什么替代方案,如果我可以更改some_function的签名,如果我不能?

简短的回答是"否"。

这里的元素std::vector<std::vector<std::vector<int> > > test;在连续存储器区域中不被替换。

您只能期望multi_dimensional_array指向大小为test[0][0].size() * sizeof(int)的连续内存块。但这可能不是你想要的。

获取矢量中任何位置的地址并将其传递是错误的。这可能看起来有效,但不要指望它。

原因与为什么向量是向量而不是数组密切相关。与数组不同,我们希望向量动态增长。我们希望插入向量是一个恒定的成本,而不是取决于向量的大小,就像数组一样,直到达到数组的分配大小。

那么魔法是如何运作的呢?当没有更多的内部空间来向向量添加下一个元素时,将分配两倍于旧空间大小的新空间。旧空间被复制到新空间,而旧空间不再需要或有效,这使得任何指向旧空间的指针都处于悬空状态。两倍的空间被分配,因此插入向量的平均成本是恒定的。

使用嵌套向量这样做安全吗?

是的,如果你只想访问最内部的向量,并且只要你知道它包含的元素数量,你就不会试图访问更多。

但看到你的函数签名,似乎你想访问所有三个维度,在这种情况下,不,这是无效的。

另一种选择是,您可以为每个最内部向量调用函数some_function(size_t size, int array[])(如果这解决了您的问题(;为此,你可以做这个技巧(或类似的东西(:

void some_function(std::vector<int> & v1int)
{
    //the final call to some_function(size_t size, int array[]) 
    //which actually process the inner-most vectors
    some_function(v1int.size(), &v1int[0]);
}
void some_function(std::vector<std::vector<int> > & v2int)
{
    //call some_function(std::vector<int> & v1int) for each element!
    std::for_each(v2int.begin(), v2int.end(), some_function);
}
//call some_function(std::vector<std::vector<int> > & v2int) for each element!
std::for_each(test.begin(), test.end(), some_function);

一个非常简单的解决方案是简单地将嵌套向量的内容复制到一个向量中,并将其传递给该函数。但这取决于你愿意承担多少开销。

可悲的是:嵌套向量S不是好的做法。将所有内容存储在连续内存中并管理访问的矩阵类实际上更高效,也不那么难看,并且可能允许类似T* matrix::get_raw()的内容,但内容的排序仍然是一个实现细节。

简单的答案-不,不是。你试过编译这个吗?为什么不把整个三维矢量作为参考呢?如果您试图以这种方式访问旧的C代码,那么您就无法访问。

传递向量或对它的引用会安全得多:

void some_function(std::vector<std::vector<std::vector<int>>> & vector);

然后,您可以获得函数中的大小和项目,从而减少出错的风险。根据预期的大小和用途,可以复制矢量或传递指针/引用。

如果您需要跨模块传递,那么它会变得稍微复杂一些。

尝试使用&top_level_vector[0]并将其传递给期望int*的C样式函数是不安全的。

为了支持对多维数组的正确C样式访问,所有数组层次结构的所有字节都必须是连续的。在c++std::vector中,对于向量包含的项,这是真的,但对于向量本身则不是。如果您尝试获取顶级向量的地址,ala &top_level_vector[0],您将得到一个向量数组,而不是int数组。

向量结构不仅仅是包含类型的数组。它被实现为一个包含指针以及大小和容量记账数据的结构。因此,问题的std::vector<std::vector<std::vector<int> > >或多或少是一个层次结构树,用指针缝合在一起。只有该树中的最后一个叶节点是连续int值的块。并且这些内存块中的每一个都不一定与任何其他块相邻。

为了与C接口,您只能传递单个vector的内容。因此,您必须创建一个大小为x * y * z的单个std::vector<int>。或者,您可以决定重新构造C代码,以便一次处理单个一维数据条。然后可以保留层次结构,只传入叶向量的内容。