C++ N nested vectors at runtime - c++

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

Related

C++ creating a 2D array using the size of a given vector, in a memory-safe manner [duplicate]

This question already has answers here:
How to create a two dimensional array of given size in C++
(3 answers)
Closed 7 years ago.
How do I achieve the following:
std::vector<int> vec = { 1, 2, 3 };
const int N = vec.size();
// Now create NxN 2D array.
First, I know I could do it with new but I'd have to remember to delete it later, and I'd rather not have to handle deallocation of memory if possible.
Second, I can't declare the 2D array on the stack because N is not (and can't be in this case) a constant expression. (In any case I'm using VS2013 and it doesn't support constexpr.)
Third, I can't (or maybe don't know how to) use std::array because apparently "a local variable cannot be used as a non-type argument". (I copy-pasted this from the VS2013 compile dialogue and have little understanding regarding this point).
Fourth, I'm thinking of using unique_ptr. The problem is, I know how to use unique_ptr for a 1D array, like std::unique_ptr<int> arr{ new int[N] }, but can't figure out how to do it for a 2D array.
Lastly, I know I can always write my own thin wrapper around a C-style array that's always created on the heap, or write my own 2D array class. But is there a native or standard library way of doing this in C++ (C++11)?
std::experimental::array_view is a view to an n-dimensional array with dynamic size bounds on a packed buffer.
So one approach is to create a contiguous buffer (say, a std::vector<T>, or a std::unique_ptr<T[]>, and then wrap an array_view<T,2> around it.
Access through the view object, and it will have the operations you should expect from an array. The storage is managed separately from the way of looking at the storage.
Writing a simplified version of this array_view for the 1 and 2 dimensional case isn't tricky. But the result is your code is high performance, and very clear at point of use. The glue code (for array_view) can be a bit tricky, but once tested it should be solid: and the likelihood that a similar construct will be added to std shortly means it won't remain obscure for long.
In my experience, once I have a solid array_view type, I use it as a drop-in replacement for where I was (inefficiently) using std::vector to pass bundles of data around in the past.
If you want to write your own, I'd skip the bits about bounds and indexes, and just implement slicing -- [] on a 2nd dimension array_view returns a 1st dimension array_view, and [] on a 1st dimension array_view returns a T&.
I suggest you write a class for it.
Example below: set() resizes it before setting values. The operator [] returns the column vector for that row, so when you apply the operator [] it returns the desired value. Let me know if you find any issue ;).
class 2DVector {
std::vector<std::vector<int>> m_items;
void set(int value, size_t row, size_t column) {
for (int i=m_items.size(); i<=row; i++) {
m_items.push_back(std::vector<int>());
}
for (int i=0; i<m_items.size(); i++) {
for (int j=m_items[i].size(); j<=column; j++) {
m_items[i].push_back(0);
}
m_items[row][column] = value;
}
std::vector<int> &operator [](size_t index) {
return m_items[index];
}
}
Usage:
2DVector v;
v.set(200, 0, 0);
v.set(201, 1, 0);
std::cout << v[0][0]; //prints 200
std::cout << v[1][0]; //prints 201
The standard library way of doing this is:
std::vector< std::vector<int> > vec2d (vec.size(), vec);
which will initialize each row with the values from vec. If you don't want to do this then leave off the final argument.
What about mimic a 2D array by 1D array?Like the way done by openCV2
pseudo codes
class 2DVector {
void set(int value, size_t row, size_t column) {
m_items[row * column_size + column];
}
int &operator [](size_t row, size_t column) {
return m_items[row * column_size + column];
}
private:
std::vector<int> m_items;
}
Or just use the boost::multi_array(Not sure about the performance is good enough for your case).

Change to n dimensions at run-time

I have a simple C++ code as below. I need to do a specific task for n dimensions. But the value of n i will get only during runt-time. How can i adpat the code to n dimesnions with vectors at run-time.
//one dimesion
std::vector<int> a;
// do some task with a;
// two dimension
std::vector< std::vector<int> > a;
// do some task with a;
.
.
Thanks
You can implement an n-dimensional array using a single vector.
This works like this:
Say your array(A[s1]) is one dimensional. Then array element is accessed like A[i1].
If your array is two dimensional(A[s1][s2]), elements A[0][0] to A[0][s2-1] are stored first and then A[1][0] to A[1][s2-1] follows. Note that all elements are stored in sequentially in single vector. So array element is accessed like A[ i1*s2 + i2 ].
For three dimensional array A[s1][s2][s3], you can think of it as s1-number of two dimensional arrays. the two-dimensional array at A[0] is stored first, then next two dimensional array at A[1] is stored and so on. So element can be accessed using A[ i1*s2*s3 + i2*s3 + i3].
An array with 'n' dimensions, can have its element accessed at [i1][i2][i3]...[in] as:
my_vector[ i1*(s2*s3*...*sn) + i2*(s3*s4*...*sn) + i3*(s4*...*sn) + ... + in ]
where s1, s2, s3, ..., sn are sizes of 1st, 2nd, ..., n-th dimension respectively.
If you want to define a generic algorithm on multidimensional vectors without knowing their dimension (see comments to the question), youd could proceed with a recursive template as in the following simple example:
template <typename T>
void myalgo(T v) // generic algorithm
{
myalgo_imp(v, static_cast<T*>(0)); // trick to distinguish vectors from non vectors
}
template <typename T>
void myalgo_imp(vector<T> cplx, vector<T> *) // vector implementation
{
for (T x : cplx) // Reaply the generic algorithm to the dimension less 1
myalgo (x);
}
template <typename T >
void myalgo_imp(T base, T*) // Apply the generic algorithm for base class (non vector)
{
cout << base << endl;
}
The trick with the static cast is explained in this SO question:
You could then use the algorithm as you've requested:
//one dimesion
std::vector<int> a(3);
myalgo(a);
// two dimension
std::vector< std::vector<int> > aa(3, vector<int>(2,1));
myalgo(aa);
This example is suitable, for example if you want to perform a base task on every base element of your multidimensional vector. Not knowing how your algorithm processes the vector, it's difficult to give a more tailored adaptation of this technique.

Making only the outer vector in vector<vector<int>> fixed

I want to create a vector<vector<int>> where the outer vector is fixed (always containing the same vectors), but the inner vectors can be changed. For example:
int n = 2; //decided at runtime
assert(n>0);
vector<vector<int>> outer(n); //outer vector contains n empty vectors
outer.push_back(vector<int>()); //modifying outer vector - this should be error
auto outer_it = outer.begin();
(*outer_it).push_back(3); //modifying inner vector. should work (which it does).
I tried doing simply const vector<vector<int>>, but that makes even the inner vectors const.
Is my only option to create my own custom FixedVectors class, or are there better ways out there to do this?
by definition,
Vectors are sequence containers representing arrays that can change in
size. Just like arrays, vectors use contiguous storage locations for
their elements, which means that their elements can also be accessed
using offsets on regular pointers to its elements, and just as
efficiently as in arrays. But unlike arrays, their size can change
dynamically, with their storage being handled automatically by the
container.
if you aren't looking to have a data structure that changes in size, a vector probably isn't the best choice for an outer layer, How about using an array of vectors. This way the array is of a fixed size and cannot be modified, while still having the freedom of having its size declared in runtime.
vector<int> *outer;
int VectSize;
cout >> "size of vector array?"
cin >> VectSize;
outer = new vector<int>[VectSize]; //array created with fixed size
outer.push_back() //not happening
Wrap the outer vector into a class which just provides at, begin, end and operator []. Let the class take only have one constructor taking its capacity.
This most probably the best way.
const vector<unique_ptr<vector<int>>> outer = something(n);
For the something, you might write a function, like this:
vector<unique_ptr<vector<int>>> something(int n)
{
vector<unique_ptr<vector<int>>> v(n);
for (auto & p : v)
p.reset(new vector<int>);
return v;
}

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.