1D Vector to Multi-dimensional array / Vector - c++

I have a 1D dimensional vector of floats I just read in from a file.
std::vector<float> result(s.size() / sizeof(float));
I want to use this data like this
myTable[rl][gl][bl][0];
So is there any easy way to convert my 1D vector to a multidimensional vector or multidimensional array that is simple?
float myTable[100][10][20][30];
vector<vector<vector<vector<int> >>> myTable;
Where I can still easily use the indexing that is setup all over the code.
and not have to convert it to a 1D access like : myTable[indexmathhere]

I wouldn't actually rewrite the data, unless you have cache requirements (though we don't know anything about the layout of your data).
Store the vector inside a class, and write an accessor function that takes four index arguments and performs the necessary arithmetic to flatten them into the single vector index.
class MyMatrix
{
std::vector<float> result;
public:
float at(int r, int g, int b, int a) const
{
return result[r+W*g+W*H*b+W*H*D*a]; // or whatevs
}
};
You could even write some operator() overloads, but you'd need three proxy types to get four dimensions of indexing out of that.

If you have fixed size array you probably should use std::array.
Something like it is in this question: Multidimensional std::array
Unfortunately, there is no oneliner to put your data into this array, you need to do it manually.

Related

iterate over std::vector of std::vector [duplicate]

I'm trying to pass a variable of type vector<vector<double> > to a function F(double ** mat, int m, int n). The F function comes from another lib so I have no option of changing it. Can someone give me some hints on this? Thanks.
vector<vector<double>> and double** are quite different types. But it is possible to feed this function with the help of another vector that stores some double pointers:
#include <vector>
void your_function(double** mat, int m, int n) {}
int main() {
std::vector<std::vector<double>> thing = ...;
std::vector<double*> ptrs;
for (auto& vec : thing) {
// ^ very important to avoid `vec` being
// a temporary copy of a `thing` element.
ptrs.push_back(vec.data());
}
your_function(ptrs.data(), thing.size(), thing[0].size());
}
One of the reasons this works is because std::vector guarantees that all the elements are stored consecutivly in memory.
If possible, consider changing the signature of your function. Usually, matrices are layed out linearly in memory. This means, accessing a matrix element can be done with some base pointer p of type double* for the top left coefficient and some computed linear index based on row and columns like p[row*row_step+col*col_step] where row_step and col_step are layout-dependent offsets. The standard library doesn't really offer any help with these sorts of data structures. But you could try using Boost's multi_array or GSL's multi_span to help with this.
The way I see it, you need to convert your vector<vector<double> > to the correct data type, copying all the values into a nested array in the process
A vector is organised in a completely different way than an array, so even if you could force the data types to match, it still wouldn't work.
Unfortunately, my C++ experience lies a couple of years back, so I can't give you a concrete example here.
Vector< Vector< double> > is not nearly the same as a double pointer to m. From the looks of it, m is assumed to be a 2-dimensional array while the vector is could be stored jagged and is not necessarily adjacent in memory. If you want to pass it in, you need to copy the vector values into a temp 2dim double array as pass that value in instead.

C++ N nested vectors at runtime

In C++ (with or without boost), how can I create an N dimensional vectors where N is determined at runtime?
Something along the lines of:
PROCEDURE buildNVectors(int n)
std::vector < n dimensional std::vector > *structure = new std::vector< n dimensional std::vector >()
END
If passed 1, a vector would be allocated. If passed 2, a 2d nested matrix would be allocated. If passed 3, a 3d cube is allocated. etc.
Unfortunately you will not be able to do this. A std::vector is a template type and as such it's type must be known at compile time. Since it's type is used to determine what dimensions it has you can only set that at compile time.
The good news is you can make your own class that uses a single dimension vector as the data storage and then you can fake that it has extra dimensions using math. This does make it tricky to access the vector though. Since you will not know how many dimensions the vector has you need to have a way to index into the container with an arbitrary number of elements. What you could do is overload the function call operator operator with a std::intializer_list which would allow you to index into it with something like
my_fancy_dynamic_dimension_vector({x,y,z,a,b,c});
A real rough sketch of what you could have would be
class dynmic_vector
{
std::vector<int> data;
int multiply(std::initializer_list<int> dims)
{
int sum = 1;
for (auto e : dims)
sum *= e;
return sum;
}
public:
dynmic_vector(std::initializer_list<int> dims) : data(multiply(dims)) {}
int & operator()(std::initializer_list<int> indexs)
{
// code here to translate the values in indexes into a 1d position
}
};
Or better yet, just use a boost::multi_array

Multidimensional Containers in C++

Is there any library provide a multidimensional container to use like vector<>?
I would like to see something like:
TwoD<object_class_name> D2;
ThreeD<object_class_name> D3;
and the object_class_name could be any object instead of only the builtin types.
so I can use the object like
D2[i][j]
D3[i,j,k] or D3(i,j,k)
or similar
Thanks.
If c++11, a possible solution is using which allows aliasing of a template:
template <typename T>
using TwoD = std::vector<std::vector<T>>;
template <typename T>
using ThreeD = std::vector<std::vector<std::vector<T>>>;
usage:
TwoD<int> t2ints;
TwoD<std::string> t2strings;
ThreeD<int> t3ints;
ThreeD<std::string> t3strings;
boost::multi_array can do that.
2D array example:
boost::multi_array<float, 2> float2D(boost::extents[5][10]);
float2D[0][0] = 1.0f;
3D array example:
boost::multi_array<float, 3> float3D(boost::extents[5][10][20]);
float2D[0][0][0] = 1.0f;
The stored type can be a class or struct as well as a primitive type, and the memory used will be contiguous.
YOu could do something like this:
std::vector<std::vector<someType> > TwoDVector;
Or a two dimensional array like these:
someType** TwoDArrayPointer;
someType TwoDArray[size][size2];
I don't like vector<vector> because each row gets its own separately allocated memory block on the heap. This causes two problems:
Iterating over all elements of the array will have very poor cache performance compared to a contiguous 2D array.
You can't pass the array into a function that wants a 1D array. For example, a lot of imaging libraries only want a char * for image data.
Therefore, I would suggest writing your own 2D array template. It's a pretty simple task. Or you can use my public domain code at github.com/jpreiss/array2d .
Also note: you can't overload operator[] with a function that takes more than one parameter. You can overload operator() for 2D indexing.
You can use vector.
// Create
vector< vector<int> > vec(4, vector<int>(4));
// Write
vec[2][3] = 10;
// Read
int a = vec[2][3];

std::vector and contiguous memory of multidimensional arrays

I know that the standard does not force std::vector to allocate contiguous memory blocks, but all implementations obey this nevertheless.
Suppose I wish to create a vector of a multidimensional, static array. Consider 2 dimensions for simplicity, and a vector of length N. That is I wish to create a vector with N elements of, say, int[5].
Can I be certain that all N*5 integers are now contiguous in memory? So that I in principle could access all of the integers simply by knowing the address of the first element? Is this implementation dependent?
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
The standard does require the memory of an std::vector to be
contiguous. On the other hand, if you write something like:
std::vector<std::vector<double> > v;
the global memory (all of the v[i][j]) will not be contiguous. The
usual way of creating 2D arrays is to use a single
std::vector<double> v;
and calculate the indexes, exactly as you suggest doing with float.
(You can also create a second std::vector<float*> with the addresses
if you want. I've always just recalculated the indexes, however.)
Elements of a Vector are gauranteed to be contiguous as per C++ standard.
Quotes from the standard are as follows:
From n2798 (draft of C++0x):
23.2.6 Class template vector [vector]
1 A vector is a sequence container that supports random access iterators. In addition, it supports (amortized) constant time insert and erase operations at the end; insert and erase in the middle take linear time. Storage management is handled automatically, though hints can be given to improve efficiency. The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
C++03 standard (23.2.4.1):
The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().
Also, see here what Herb Sutter's views on the same.
As #Als already pointed out, yes, std::vector (now) guarantees contiguous allocation. I would not, however, simulate a 2D matrix with an array of pointers. Instead, I'd recommend one of two approaches. The simpler by (by far) is to just use operator() for subscripting, and do a multiplication to convert the 2D input to a linear address in your vector:
template <class T>
class matrix2D {
std::vector<T> data;
int columns;
public:
T &operator()(int x, int y) {
return data[y * columns + x];
}
matrix2D(int x, int y) : data(x*y), columns(x) {}
};
If, for whatever reason, you want to use matrix[a][b] style addressing, you can use a proxy class to handle the conversion. Though it was for a 3D matrix instead of 2D, I posted a demonstration of this technique in previous answer.
For reference the way I currently create a 2D array in a contiguous memory block is by first making a (dynamic) array of float* of length N, allocating all N*5 floats in one array and then copying the address of every 5th element into the first array of float*.
That's not a 2D array, that's an array of pointers. If you want a real 2D array, this is how it's done:
float (*p)[5] = new float[N][5];
p [0] [0] = 42; // access first element
p[N-1][4] = 42; // access last element
delete[] p;
Note there is only a single allocation. May I suggest reading more about using arrays in C++?
Under the hood, a vector may look approximately like (p-code):
class vector<T> {
T *data;
size_t s;
};
Now if you make a vector<vector<T> >, there will be a layout like this
vector<vector<T>> --> data {
vector<T>,
vector<T>,
vector<T>
};
or in "inlined" form
vector<vector<T>> --> data {
{data0, s0},
{data1, s1},
{data2, s2}
};
Yes, the vector-vector therefore uses contiguous memory, but no, not as you'd like it. It most probably stores an array of pointers (and some other variables) to external places.
The standard only requires that the data of a vector is contiguous, but not the vector as a whole.
A simple class to create, as you call it, a 2D array, would be something like:
template <class T> 2DArray {
private:
T *m_data;
int m_stride;
public:
2DArray(int dimY, int dimX) : m_stride(dimX) : m_data(new[] T[dimX * dimY]) {}
~2DArray() { delete[] m_data; }
T* operator[](int row) { return m_data + m_stride * row; }
}
It's possible to use this like:
2DArray<int> myArray(30,20);
for (int i = 0; i < 30; i++)
for (int j = 0; j < 20; j++)
myArray[i][j] = i + j;
Or even pass &myArray[0][0] as address to low-level functions that take some sort of "flat buffers".
But as you see, it turns naive expectations around in that it's myarray[y][x].
Generically, if you interface with code that requires some sort of classical C-style flat array, then why not just use that ?
Edit: As said, the above is simple. No bounds check attempts whatsoever. Just like, "an array".

How to Implement a multidimensional array if the dimension is unknown at compile-time?

I want to implement a function that gets as a parameter a dimension "n" of an array of integers. This function also gets values "k_1, k_2, ..., k_n" defining the size of the array. Then this function will fill this n-dimensional array.
How do I implement this efficiently with C++?
For example for n = 3 I would use
vector < vector < vector < int > > > array;
But I don't know the dimension at compile time.
Use a one-dimensional array, and fake the other dimensions using multiplication of offsets for indexing, and you can pass the dimension sizes in by vector, i.e.
std::vector<int> create_md_array(const std::vector<int> & dimensions)
{
int size = std::accumulate(dimensions.begin(), dimensions.end(), 1, std::multiplies<int>());
return std::vector<int>(size);
}
You have a couple of choices. You can implement it yourself, basically multiplying the coordinates by the sizes to linearize the multi-dimensional address, and just have a simple std::vector<whatever> to hold the data.
Alternatively, you could use std::valarray and friends to accomplish the same. It has a set of classes that are specifically intended for the kind of situation you describe -- but they're used so rarely that almost nobody understands them. Writing the code yourself stands a good chance of being easier for most people to read and understand.