Multi-dimensional vector initialization - c++

I have following std::vector declaration:
std::vector<std::vector<std::vector<int> > > m_input;
I am initializing it as follows:
m_input.resize (100);
m_output.resize(100);
for (int i = 0; i < 100; ++i) {
m_input [i].resize(100);
m_output[i].resize(100);
for (int j = 0; j < 100; ++j){
m_input [i][j].resize(100);
m_output[i][j].resize(100);
}
}
How can I achieve this via the member initializer list?

std::vector<T> has a constructor that takes two arguments, a number of elements and an initial value. In your case, you want to initialize m_input with 100 copies of a std::vector<std::vector<int> > , so it'd be : m_input(100, X). Now, that X in turn is a vector of 100 std::vector<int>, which in turn contains a hundred ints:
: m_input(100, std::vector<std::vector<int> >(100, std::vector<int>(100, 0)))

my_class::my_class()
: m_input(100, std::vector< std::vector<int> >(100, std::vector<int>(100) ))
{
}
That said, implementing a multi-dimensional field should be done by projecting into a one-dimensional one, as Viktor said in his comment to the question.

If you can assert that your vector dimensions are going to be of a fixed length, then why not use std::array?
For example:
std:array<std::array<std::array<int, 100>, 100>, 100>
That way you can take advantage of all the memory being contiguously allocated (as hinted at by Viktor_Sehr in the comments), without the added implementation woes of accessing a 1-dimensional array in a 3-dimensional way.

Related

Is there a way to declare an array of std::vector of a certain size?

I want to declare an array of vectors of a certain length. To declare an array of vectors, I write this, for instance:
std::vector<double> myarray[17][38][42];
This creates a 3-dimensional 17x38x24 array, where each element is of type std::vector<double>.
I also know that to specify the size of a std::vector I may write, for instance:
std::vector<double> myvector(14);
This creates a std::vector with space allocated for 14 elements.
I run into a problem when I try to combine these two procedures. For example, writing:
std::vector<double> myarray[17][38][42](14);
I receive this error:
error: array must be initialized with a brace-enclosed initializer [-fpermissive]
std::vector<double> myarray[17][38]42;
When I try to initialize it this way:
std::vector<double> myotherarray(14)[17][38][42];
I receive this error:
error: expected ‘,’ or ‘;’ before ‘[’ token
std::vector<double> myotherarray(14)[17][38][42];
What is the proper way to declare every element of the array to be a std::vector of a certain size?
You can't initialize such a multi-dimensional array the way you want. But you can declare it first and then use a separate initialization loop instead, eg:
std::vector<double> myarray[17][38][42];
for(size_t i = 0; i < 17; ++i) {
for(size_t j = 0; j < 38; ++j) {
for(size_t k = 0; k < 42; ++k) {
myarray[i][j][k].resize(14);
}
}
}
Or:
std::vector<double> myarray[17][38][42];
for(auto &d1 : myarray) {
for(auto &d2 : d1) {
for(auto &elem : d2) {
elem.resize(14);
}
}
}
But, if you already know the vector size at compile-time, why use std::vector at all? You can use std::array instead, eg:
std::array<double, 14> myarray[17][38][42];
You have an array of (array of array of) vectors, so if you want to inialize it, you have to use brace initializer list, and you have to initialize each vector element (effectively 38* 42 * 14 vectors!) explicitly. This doesn't seem feasible.
If you only want to initialize the very first vector in the array (of arrays of arrays) (or a very few vectors) you can do this:
std::vector<double> vec[17][38][42]{{{std::vector<double>(14)}}};
But from practical standpoint, you'd have to iterate over those arrays of vectors in a loop and resize them.

C++ vector of fixed size vecors

How can I declare vector of fixed size vectors in C++?
For example:
vector of vectors with N elements.
Not this:
vector<vector<int> > v(N) //declares vector of N vectors
std::array is your friend here.
http://en.cppreference.com/w/cpp/container/array
For instance, to declare vector of vectors with N elements, you can
typedef std::array<int, N> N_array;
Then use
std::vector<N_array>
You could use std::array:
std::array<int, 10> myNumbers;
The only down side to this is you can't see how many "active" elements there are, since you don't push/emplace back. You use it like an ordinary( but safe ) array.
If you wish to have vector of fixed size, most likely you don't need one! Use std::array instead.
But still you insist to have one..
vector<vector<int> > vecOfVec(NumberOfVectors);
for ( int i = 0 ; i < NumberOfVectors; i++ )
vecOfVec[i].resize(NumberOfElementsInVector);

Pointer to a multidimensional vector

I am trying to initialize a pointer (*vectorName) with a 2D vector 366 by 4.
Both
vector<int> *vectorName = new vector<int>(366, new vector<int>(4));
and
vector<int> *vectorName = new vector<int>(366, vector<int>(4));
do not work and give me the error
Error: no instance of constructor "std::vector, <_Ty, _Alloc>::vector [with_ty=int, _Alloc=std_allocator]"
argument types are (const int, std::vector>*)
What can I do?
This is happening within the main function.
vector<int> *vectorName = new vector<int>(366, vector<int>(4));
The above doesn't work because the vector constructor template (ignoring a few things) looks as follows:
vector <TYPE> (SIZE, variable of type TYPE);
And in vector<int>(366, vector<int>(4)), vector <int> (4) is not of type int.
To create a vector with 366 elements that are vector of ints of size 4:
vector<vector<int> > *vectorName = new vector<vector<int> >(366, vector<int>(4));
or, if you don't need a pointer: (which you quite possibly don't)
vector<vector<int> > vectorName(366, vector<int>(4));
As a side note, if it's a fixed size 2D vector, why are you using vector, and not just an array. This would be much simpler:
int arr[366][4];
I assume that you're trying to use a pointer to a vector in order to get a dynamic C-array of vectors. There's no reason to do that. You can use a vector of vectors instead:
vector< vector<int> >
You can initialize that like this:
vector< vector<int> > vec(4);
for (size_t i = 0; i < 4; ++i) {
vec[i].resize(366);
}
Usage example:
vec[3][365] = 3;
If however you really do want a pointer to such a vector:
vector< vector<int> >* vec = new vector< vector<int> >(4);
for (size_t i = 0; i < 4; ++i) {
(*vec)[i].resize(366);
}
(*vec)[3][365] = 3;
If your size is constant and you're using a C++11 compiler, you can use an easier way, std::array:
array<array<int, 366>, 4> arr;
// Usage example
arr[3][365] = 3;
Or a pointer to a dynamically allocated one:
array<array<int, 366>, 4>* arr = new array<array<int, 366>, 4>;
// Usage example
(*arr)[3][365] = 3;
Are you trying to do this? This makes a 2D vector of vectors with int. It creates 366 vectors with a vector with size 4,where all items are initialized to zero. Now you have a 2D vector of 366 by 4.
vector<vector<int> > twod( 366, vector<int>(4,0));
and if you would like a pointer to this vector:
vector<vector<int> >* twodptr = &twod;
if you would really need this.

to pass RAII structure as 2D-array into a function

There is a function, accepting 2D-array:
void foo ( double ** p )
{ /*writing some data into p*/ }
I wouldn't like to pass raw 2D array into this function because i don't want to manage memory calling new and delete. Also i wouldn't like to change function signature to void foo ( std::vector< std::vector<double> >& ). And i can't make foo as a template function (in my project it's a COM-interface method).
I would like to pass some RAII object decoring it raw-one, like
void foo ( double * p ){}
std::vectore<double> v(10);
p( &v[0] );
Is there way to do this for 2D-arrays? I tried
std::vector< std::vector<int> > v;
foo( &v[0][0] )
and
std::vector< std::tr1::shared_ptr<int> > v;
but i get compile errors error C2664 - cannot convert parameter.
Also, can one be sure that raw address arithmetics inside the function works ok in this case?
No C++11, the sizes of 2D-array are known.
One possible solution is to change:
std::vector< std::vector<int> > v;
foo( &v[0][0] )
to
std::vector< std::vector<int> > v;
std::vector<int*> v_ptr;
for (...) {
v_ptr[i] = &v[i][0];
}
foo( &v_ptr[0])
Although Andreas already gave an answer to your question that solves your particular problem, I would like to point out, that although that works, it is probably not what you want to do.
As you are using C++ (and not an easier to use language), I am assuming that you care about performance. In that case your approach is in all likelihood wrong from the beginning, as double** represents an array of arrays (or rather can represent) and not a 2D array. Why is this bad? Because, just as with the std::vector< std::vector<int> > example, multiple allocations are required, and the resulting memory is non-contiguous (which is bad for the cache) unlike a double array[N][M].
For 2D arrays you should in fact use 1D arrays with index calculation, which is far more cache-friendly. This of course does not allow [x][y]-style indexing (instead you have to use [x+N*y] or [y+M*x], depending on your choice of "Fortran order" or "C order"), but avoids cache issues and only requires a single allocation (and a simple double*pointer).
If you are iterating all elements of the array as in
for(unsigned x = 0; x < N; ++x) for(unsigned y = 0; y < M; ++y)
{
unsigned idx = y + M * x;
p[idx] = bar(x, y); // equivalent to p[x][y] = bar(x,y) in the array-of-arrays case
}
You can even avoid the multiplications as this is basically just a 1D iteration with additional generation of 2D indices
for(unsigned x = 0, idx = 0; x < N; ++x) for(unsigned y = 0; y < M; ++y, ++idx)
{
p[idx] = bar(x, y);
}

newbie question about pointer to stl

I have written this function
vector<long int>* randIntSequence(long int n) {
vector<long int> *buffer = new vector<long int>(n, 0);
for(long int i = 0; i < n; i++)
buffer->at(i);
long int j; MTRand myrand;
for(long int i = buffer->size() - 1; i >= 1; i--) {
j = myrand.randInt(i);
swap(buffer[i], buffer[j]);
}
return buffer;
}
but when I call it from main, myvec = randIntSequence(10), I see the myvector always empty. Shall I modify the return value?
The swap call is indexing the *buffer pointer as if it were an array and is swapping around pointers. You mean to swap around the items of the vector. Try this modification:
swap((*buffer)[i], (*buffer)[j]);
Secondary to that, your at calls don't set the values as you expect. You are pulling out the items in the vector but not setting them to anything. Try one of these statements:
buffer->at(i) = i;
(*buffer)[i] = i;
You never assign to any of the elements in the vector pointed to by buffer:
for (long int i = 0; i < n; i++)
buffer->at(i); // do you mean to assign something here?
You end up with the vector containing n zeroes.
Your question has already been answered, so I'll make this CW, but this is how your code should look.
std::vector<long int> randIntSequence(long int n)
{
std::vector<long int> buffer(n);
for(int i=0; i<n; ++i)
buffer[i] = i;
std::random_shuffle(buffer.begin(), buffer.end());
return buffer;
}
There is absolutely no reason you should be using a pointer here. And unless you have some more advanced method of random shuffling, you should be using std::random_shuffle. You might also consider using boost::counting_iterator to initialize the vector:
std::vector<long int> buffer(
boost::counting_iterator<long int>(0),
boost::counting_iterator<long int>(n));
Though that may be overkill.
Since the question is about STL, and all you want is a vector with random entries then:
std::vector<long int> v(10);
generate( v.begin(), v.end(), std::rand ); // range is [0,RAND_MAX]
// or if you provide long int MTRand::operator()()
generate( v.begin(), v.end(), MTRand() );
But if you want to fix your function then
n should be size_t not long int
First loop is no-op
As John is saying, buffer is a pointer, so buffer[0] is your vector, and buffer[i] for i!=0 is garbage. It seems you have been very lucky to get a zero-sized vector back instead of a corrupt one!
Is your intention to do random shuffle? If yes, you are shuffling around zeros. If you just want to generate random entries then why don't you just loop the vector (from 0 to buffer->size(), not the other way around!!) and assign your random number?
C++ is not garbage collected, and you probably don't want smart pointers for such simple stuff, so you'll be sure to end up with leaks. If the reason is in generating a heap vector and returning by pointer is avoiding a copy for performance's sake, then my advise is don't do it! The following is the (almost) perfect alternative, both for clarity and for performance:
vector<T> randIntSequence( size_t n ) {
vector<T> buffer(n);
// bla-bla
return buffer;
}
If you think there is excess copying around in here, read this and trust your compiler.