is initializing an n-dimensional vector with constructor bad? - c++

So, I recently figured out, that we can initialize an n sized vector with default values by writing e.g. vector<int> x(n, default_value).
This can also be applied to n dimensional vectors, e.g. n=3:
vector<vector<vector<int>>> x(n, vector(n, vector(n, default_value)))
Has this approach any advantages or disadvantages over doing:
vector<vector<vector<int>>> x;
x.resize(n);
for (int i = 0; i < n; i++)
{
x[i].resize(n);
for (int j = 0; j < n; j++)
{
x[i][j].resize(n);
}
}

The first one first creates default_value for each vector and then copies it to the destinations, so you get (n+1)^k allocations instead of n^k.
You forgot to initialize the integer-based vector. Therefore I argue the first version is less error-prone ;) It's also much cleaner and shows the intention clearly.
Although second could benefit from for(auto& c:vec) loops instead of indices. Or std::for_each, or any other loop-hiding stuff... Anyway you are doing initialization -> just use constructors.

Related

Initializing multi-dimensional std::vector without knowing dimensions in advance

Context: I have a class, E (think of it as an organism) and a struct, H (a single cell within the organism). The goal is to estimate some characterizing parameters of E. H has some properties that are stored in multi-dimensional matrices. But, the dimensions depend on the parameters of E.
E reads a set of parameters from an input file, declares some objects of type H, solves each of their problems and fills the matrices, computes a likelihood function, exports it, and moves on to next set of parameters.
What I used to do: I used to declare pointers to pointers to pointers in H's header, and postpone memory allocation to H's constructor. This way, E could pass parameters to constructor, and memory allocation could be done afterwards. I de-allocated memory in the destructor.
Problem: Yesterday, I realized this is bad practice! So, I decided to try vectors. I have read several tutorials. At the moment, the only thing that I can think of is using push_back() as used in the question here. But, I have a feeling that this might not be the best practice (as mentioned by many, e.g., here, under method 3).
There are tens of questions that are tangent to this, but none answers this question directly: What is the best practice if dimensions are not known in advance?
Any suggestion helps: Do I have any other solution? Should I stick to arrays?
Using push_back() should be fine, as long as the vector has reserved the appropriate capacity.
If your only hesitancy to using push_back() is the copy overhead when a reallocation is performed, there is a straightforward way to resolve that issue. You use the reserve() method to inform the vector how many elements the vector will eventually have. So long as
reserve() is called before the vector is used, there will just be a single allocation for the needed amount. Then, push_back() will not incur any reallocations as the vector is being filled.
From the example in your cited source:
std::vector<std::vector<int>> matrix;
matrix.reserve(M);
for (int i = 0; i < M; i++)
{
// construct a vector of ints with the given default value
std::vector<int> v;
v.reserve(N);
for (int j = 0; j < N; j++) {
v.push_back(default_value);
}
// push back above one-dimensional vector
matrix.push_back(v);
}
This particular example is contrived. As #kei2e noted in a comment, the inner v variable could be initialized once on the outside of the loop, and then reused for each row.
However, as noted by #Jarod42 in a comment, the whole thing can actually be accomplished with the appropriate construction of matrix:
std::vector<std::vector<int>> matrix(M, std::vector<int>(N, default_value));
If this initialization task was populating matrix with values from some external source, then the other suggestion by #Jarod42 could be used, to move the element into place to avoid a copy.
std::vector<std::vector<int>> matrix;
matrix.reserve(M);
for (int i = 0; i < M; i++)
{
std::vector<int> v;
v.reserve(N);
for (int j = 0; j < N; j++) {
v.push_back(source_of_value());
}
matrix.push_back(std::move(v));
}

C++ : How to safely deallocate a heap-allocated array of vectors?

I am currently working with code that at the moment requires me to make an array of vectors (I am new to C++ - if this is an absolutely terrible idea, I would greatly appreciate the feedback).
Let's say I allocate memory on the heap for my vectors like so:
#include <iostream>
#include <vector>
#include <random>
int main() {
typedef std::vector<double> doubleVec;
long N = 1000;
long M = 1000;
doubleVec *array = new doubleVec[N];
for (long i = 0; i < N; i++) {
doubleVec currentVec = array[i];
currentVec.resize(M);
for (long j = 0; j < M; j++)
currentVec[j] = std::rand();
}
// ... do something with the data structure
delete [] array;
}
When I've done everything I need to do with the data, how should I safely deallocate this data structure?
NOTE: There were other things I did wrong in my inital post that I didn't intend to be the focus of the discussion (uninitialized variables, didn't resize vectors, etc). I fixed those now. Thank you all for pointing those out.
f this is an absolutely terrible idea, I would greatly appreciate the feedback).
Yes, this is a terribly bad idea. To be specific, owning bare pointers are a bad idea. Instead of manually allocating a dynamic array, it is usually better to use a container such as std::vector.
How to safely deallocate a heap-allocated array of vectors?
By using a vector instead of manual dynamic array. In this case, a simple solution is to use a vector of vectors.
A potentially better solution would be to allocate a single flat vector of doubles of size 1000*1000 where elements of each "subvector" is after another. This requires a bit of simple math to calculate the index of the sub vectors, but is in most use cases faster.
Other notes:
typedef std::vector<double> doubleVec;
Avoid obfuscating the program by hiding type names like this.
for (long j; j < M; j++)
^^^^^^
You leave this variable uninitialised. When the indeterminate value is used later, the behaviour of the program is undefined.
Furthermore, you forgot to include the standard headers which define std::vector and std::rand.
I got a seg fault
See the other answer regarding you not actually adding any elements to the vectors that are in the array. This, and the uninitialised variables are the most likely reason for your segfault depending on what "do something" does.
The problem is not in deallocating but in each vector allocation. Where in your code do you use the M value (except while accessing the elements)? There are other problems in your code, so the quick fix is:
for (long i; i < N; i++) {
doubleVec &currentVec = array[i];
currentVec.resize(M);
for (long j; j < M; j++)
currentVec[j] = std::rand();
}
Pay special attention that currentVec is a reference: otherwise no changes would be stored in the array.
Anyway, the main question everybody would have is: why do you need to have an array of vectors?.. The vector of vectors is a much more elegant solution.
Update: I've missed the fact that you have forgotten to initialize both i and j. In addition to the advice to initialize them I would recommend to use the auto keyword that would make it impossible to leave the variable uninitialized:
for (auto i=0UL; i < N; i++) {
doubleVec &currentVec = array[i];
currentVec.resize(M);
for (auto j=0UL; j < M; j++)
currentVec[j] = std::rand();
}
0UL means zero of the type unsigned long.

Populating a vector with known number of elements: specify its size in constructor or by using reserve method?

I would like to create a vector of some complex type, by reading individual elements from a stream. I know the vector size in advance. Is it better to specify the number of elements in the vector constructor or by using reserve method? Which one of these two is better?
int myElementCount = stream.ReadInt();
vector<MyElement> myVector(myElementCount);
for (int i = 0; i < myElementCount; i++)
{
myVector[i] = stream.ReadMyElement();
}
or
int myElementCount = stream.ReadInt();
vector<MyElement> myVector;
myVector.reserve(myElementCount);
for (int i = 0; i < myElementCount; i++)
{
myVector.push_back(stream.ReadMyElement());
}
What about the case where I just create a vector of ints or some other simple type.
It depends on what MyElement is, especially what its operator= does, so it's largely the usual "try both and use the faster one for you". There is a third choice, use c++11 and emplace_back, especially if MyElement is heavy.
As a datapoint, for int or double I found that using the constructor (or resize()) and [] is faster. Specifically, this way the loop is much easier for the compiler to vectorize.

Inner-loop using vector.size() leads to infinite loop

I am trying to avoid copying with vectors, so I am (I know -- poor practice) mutating the vector while I loop over it, but I have noticed that it evaluates size() at every loop end. Furthermore, even if I declare it outside of the loop and assign it to another variable, it still reevaluates. Even more surprising, even if I declare it const, it reevaluates. Can someone tell me why this is the case? And what is the best way to add to a vector without creating a separate one, then combining them after each inner loop completes? Sample code:
#include <vector>
int main()
{
std::vector<int> v {0};
// infinite loop
for (int i = 0; i < 100; ++i)
{
const size_t sz = v.size();
for (size_t j = 0; j < sz; ++j)
v.push_back(i);
}
return 0;
}
I believe you are trying to avoid memory reallocation with vectors.
If this is the case you should use reserve(n): it preallocate memory for n elements thus avoiding memory reallocation while it have n elements or less. When you reach n+1 elements it may reallocate.
I'd like to ask you to be more specific: what are you expecting from your code?

C++ : efficient copy of a list of vectors in a vector

I am looking for the most efficient way to copy the content of a list of vectors in a vector. I want to avoid as far as possible memory reallocation.
My problem is the following :
I have :
a std::vector<int> v containing N elements
a list of vector std::vector< std::vector<int>* > vlist
and I know that the total number of elements M in the vectors of vlist is <= N
(N and M can be very large)
I want to copy all the elements of vlist in v (first all the elements of vlist[0], then all the elements of vlist[1] etc...) and at the end reduce the v size to M (my project don't use C++2011).
How to do that as efficiently as possible ?
Thank you very much.
EDIT : remark : v is already filled with N elements and I want to replace them with M (<= N) elements coming from the other vectors.
I have no idea if this is the most efficient way, but this is a way:
std::vector<int> v;
std::vector< std::vector<int>* > vlist;
int j = 0;
for(int i = 0; i < vlist.size(); ++i) {
std::copy(vlist[i]->begin(), vlist[i]->end(), &v[j]);
j += vlist[i]->size();
}
v.resize(j);
If you really want the most efficient way, you might have to implement several different ways and compare their speeds.
The most efficient way is to not copy it. What is your application doing that requires it? Also, why do you have a vector<* vector<int> > instead of just vector<vector<int> > ? Design around it, use pimpl, lazy copy, etc.
And in the end I'm not sure what you think you can do that's going to beat std's default copy constructor. Have you profiled your application to determine the default ctor is a bottleneck?
std::vector<int> v;
v.reserve(N);
for(size_t i = 0; i<vlist.size(); i++)
{
v.insert(v.end(), vlist[i]->begin(), vlist[i]->end());
}
This should be efficient enough if M is close to N. Otherwise it's better to compute M before allocating the memory, and use v.reserve(M).