Pass nested C++ vector as built-in style multi-dim

2019-07-13 00:20发布

If I have a vector in C++, I know I can safely pass it as an array (pointer to the contained type):

void some_function(size_t size, int array[])
{
    // impl here...
}

// ...
std::vector<int> test;
some_function(test.size(), &test[0]);

Is it safe to do this with a nested vector?

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]);

Edit:

If it is not safe, what are some alternatives, both if I can change the signature of some_function, and if I can't?

8条回答
祖国的老花朵
2楼-- · 2019-07-13 01:06

Trying to use &top_level_vector[0] and pass that to a C-style function that expects an int* isn't safe.

To support correct C-style access to a multi-dimensional array, all the bytes of all the hierarchy of arrays would have to be contiguous. In a c++ std::vector, this is true for the items contained by a vector, but not for the vector itself. If you try to take the address of the top-level vector, ala &top_level_vector[0], you're going to get an array of vectors, not an array of int.

The vector structure isn't simply an array of the contained type. It is implemented as a structure containing a pointer, as well as size and capacity book-keeping data. Therefore the question's std::vector<std::vector<std::vector<int> > > is more or less a hierarchical tree of structures, stitched together with pointers. Only the final leaf nodes in that tree are blocks of contiguous int values. And each of those blocks of memory are not necessarily contiguous to any other block.

In order to interface with C, you can only pass the contents of a single vector. So you'll have to create a single std::vector<int> of size x * y * z. Or you could decide to re-structure your C code to handle a single 1-dimensional stripe of data at a time. Then you could keep the hierarchy, and only pass in the contents of leaf vectors.

查看更多
疯言疯语
3楼-- · 2019-07-13 01:07

It is erroneous to take the address of any location in a vector and pass it. It might seem to work, but don't count on it.

The reason why is closely tied to why a vector is a vector, and not an array. We want a vector to grow dynamically, unlike an array. We want insertions into a vector be a constant cost and not depend on the size of the vector, like an array until you hit the allocated size of the array.

So how does the magic work? When there is no more internal space to add a next element to the vector, a new space is allocated twice the size of the old. The old space is copied to the new and the old space is no longer needed, or valid, which makes dangling any pointer to the old space. Twice the space is allocated so the average cost of insertion to the vector that is constant.

查看更多
登录 后发表回答