push_back an object into vector - c++

I have a vector of objects (vector<Vertex> setOfVertices) and I want to create a specified number of new objects of in this vector. Is this a proper way to do so?
for (int i = 0; i < 10; i++)
setOfVertices.push_back(Vertex());
or is it better to do it like this:
for (int i = 0; i < 10; i++)
{
Vertex * V = new Vertex();
setOfVertices.push_back(*V);
}
Do I need to write some kind of destructor in the latter case?
Or would it be better to give up on std:vector and use arrays instead?

The second example has a memory leak.
If what you want is just a "fill" function then setOfVertices.insert(setOfVertices.end(), 10, Vertex()); is good enough.
However, if what you want instead is insert different Vertex objects then
// Make sure only a single memory allocation takes place.
setOfVertices.reserve(setOfVertices.size() + 10);
for (int i = 0; i < 10; i++)
setOfVertices.push_back(Vertex(i));

You can use the "fill" overload of std::vector::insert:
setOfVertices.insert(setOfVertices.end(), 10, Vertex());
There's no need to allocate memory yourself, std::vector will do that for you. All you need to do is pass a "reference" Vector for the new elements to copy from.

Related

How to use memset or fill_n to initialize a dynamic two dimensional array in C++

I have a 2D array created dynamically.
int **abc = new int*[rows];
for (uint32_t i = 0; i < rows; i++)
{
abc[i] = new int[cols];
}
I want to fill the array with some value (say 1). I can loop over each item and do it.
But is there a simpler way. I am trying to use memset and std::fill_n as mentioned in this post.
std::fill_n(abc, rows * cols, 1);
memset(abc, 1, rows * cols * sizeof(int));
Using memset crashes my program. Using fill_n gives a compile error.
invalid conversion from 'int' to 'int*' [-fpermissive]
What am I doing wrong here ?
You could just use vector:
std::vector<std::vector<int>> abc(rows, std::vector<int>(cols, 1));
You cannot use std::fill_n or memset on abc directly, it simply will not work. You can only use either on the sub-arrays:
int **abc = new int*[rows];
for (uint32_t i = 0; i < rows; i++)
{
abc[i] = new int[cols];
std::fill_n(abc[i], cols, 1);
}
Or make the whole thing single-dimensional:
int *abc = new int[rows * cols];
std::fill_n(abc, rows*cols, 1);
Or I guess you could use std::generate_n in combination with std::fill_n, but this just seems confusing:
int **abc = new int*[rows];
std::generate_n(abc, rows, [cols]{
int* row = new int[cols];
std::fill_n(row, cols, 1);
return row;
});
I think that your main problem here is that you don't have an array of int values. You have an array of pointers to ints.
You probably should start with int* abc = new int[rows * cols]; and work from there, if I understand what you are trying to achieve here.
Just use with * inside the loop you already have:
for (uint32_t i = 0; i < rows; i++)
{
abc[i] = new int[cols];
std::fill_n(*(abc+i), cols, sizeof(int));
}
fill_n don't know where the memory maps the new int array, so you must be carefully coding that way.
I recommend to read:
A proper way to create a matrix in c++
Since you've already got good, workable answers to solve your problem, I want to add just two pointers left and right from the standard path ;-)
a) is just a link to the documentation of Boost.MultiArray
and b) is something I don't recommend you use, but it might help you to understand what you've initially tried. And since your profile shows visual studio tags, you might come in contact with something like this in the win32 api. If that is the case the documentation usually tells you not to use free()/LocalFree()/... on the elements and the "outer" pointer-pointer but to use a specialized function.
(note: I'm not trying to make this code look pretty or clever; it's a mishmash of c and a little c++-ish junk ;-))
const std::size_t rows = 3, cols =4;
int main()
{
std::size_t x,y;
// allocate memory for 0...rows-1 int* pointers _and_ cols*rows ints
int **abc = (int**)malloc( (rows*sizeof(int*)) + cols*rows*sizeof(int) );
// the memory behind abc is large enough to hold the pointers for abc[0...rows-1]
// + the actual data when accessing abc[0...rows-1][0....cols-1]
int* data = (int*)((abc+rows));
// data now points to the memory right after the int*-pointer array
// i.e. &(abc[0][0]) and data should point to the same location when we're done:
// make abc[0] point to the first row (<-> data+(cols*0)), abc[1] point the second row (<-> data+(cols*1)....
for(y=0;y<rows; y++) {
abc[y] = &(data[y*cols]);
}
// now you can use abc almost like a stack 2d array
for(y=0; y<rows; y++) {
for (x=0; x<cols; x++) {
abc[y][x] = 127;
}
}
// and -since the memory block is continuos- you can also (with care) use memset
memset(&abc[0][0], 1, sizeof(int)*rows*cols);
// and with equal care ....
std::fill_n( &(abc[0][0]), rows*cols, 127);
// and get rid of the whole thing with just one call to free
free(abc);
return 0;
}

Copy y-components of a vector

I want to copy the y-components of a vector of the type: std::vector <glm::vec3> example because I can't access only the y-components of this vector by doing something like example.size().y.... So, I assume I have to copy the content of the y-components to another another vector/array, but is there a way to do that? I was thinking of something like:
std::vector <int> something;
for (int i = 0; i < example.size(); i++)
{
something[i] = example[i].y;
}
but it doesn't work apparently.
Thanks!
You need to make sure the size of the vector grows along with the elements you push into them. The [] operator is only an accessor.
std::vector <int> something;
something.resize(example.size());
for (int i = 0; i < example.size(); i++)
{
something[i] = example[i].y;
}
std::vector <int> something;
for (int i = 0; i < example.size(); i++)
{
something[i] = example[i].y;
}
Two issues:
glm::vec3 is a floating-point type, and example[i].y is going to return a floating point value. And if these are normalized model vertices, they're very likely all in the range [-1,1], which means that something[i] would always be assigned -1, 0, or 1.
something never has its memory initialized in the code snippet you're providing. That will cause runtime crashes. You should be writing something like
std::vector<float> something(example.size());

Storing a 3D VLA on heap

I need to store an array on heap since I got a seg fault when running the program, due to it being too large. Normally this would be easy, but in this case it is a multidimensional array (3D specifically) and it's a variable length array too.
I tried to fit this answer for a 2D array (which I'm pretty sure works because I found it on another answer on SO) into one for a 3D array
int **ary = new int*[sizeY];
for(int i = 0; i < sizeY; ++i) {
ary[i] = new int[sizeX];
}
by doing this:
double **isoarray = new double*[nBinsX];
for(int xi = 0; xi < nBinsX; ++xi){
isoarray[xi] = new double[nBinsY];
for(int yi = 0; yi < nBinsY; ++yi){
isoarray[xi][yi] = new double[nShuffles];
}
}
Where I should mention that the array is meant to have dimensions nBinsX x nBinsY x nShuffles, but it isn't working, nor did I really think it would to be honest. Can anyone offer a suggestion on how I would do this? Thanks in advance!
Rather than heap-allocating arrays of pointers to more heap-allocated arrays and so on, you should make a single giant allocation and do appropriate indexing. This is a common technique:
double *isoarray = new double[nBinsX * nBinsY * nShuffles];
If you want to make a nice C++ solution out of it, store that pointer in a class which has an indexing method something like this:
double& at(x, y, shuffle) {
return isoarray[x * nBinsY * nShuffles + y * nShuffles + shuffle];
}
This way you have a single contiguous allocation which is better for performance when allocating, when using, and when deallocating. You can play with the indexing in terms of which dimension comes "first" to achieve even better performance depending on which way you usually traverse the data.

How to initialize an empty global vector in C++

I have a general question. Hopefully, one of you has a good approach to solve my problem. How can I initialize an empty vector?
As far as I read, one has to know the size of an array at compiling time, though for vectors it is different. Vectors are stored in the heap (e.g. here: std::vector versus std::array in C++)
In my program I want to let the client decide how accurate interpolation is going to be done. That's why I want to use vectors.
The problem is: For reasons of clear arrangement I want to write two methods:
one method for calculating the coefficients of an vector and
one method which is providing the coefficients to other functions.
Thus, I want to declare my vector as global and empty like
vector<vector<double>> vector1;
vector<vector<double>> vector2;
However, in the method where I determine the coefficients I cannot use
//vector containing coefficients for interpolation
/*vector<vector<double>>*/ vector1 (4, vector<double>(nn - 1));
for (int ii = 0; ii < nn - 1; ii++) {vector1[ii][0] = ...;
}
"nn" will be given by the client when running the program. So my question is how can I initialize an empty vector? Any ideas are appreciated!
Note please, if I call another function which by its definition gives back a vector as a return value I can write
vector2= OneClass.OneMethod(SomeInputVector);
where OneClass is an object of a class and OneMethod is a method in the class OneClass.
Note also, when I remove the comment /**/ in front of the vector, it is not global any more and throws me an error when trying to get access to the coefficients.
Use resize:
vector1.resize(4, vector<double>(nn - 1));
Use resize() function as follows:
vector<vector<double>> v;
int f(int nn){
v.resize(4);
for(int i = 0; i < 4; i++){
v[i].resize(nn - 1);
}
}
It look to me that you're actually asking how to add items to your global vector. If so this might help:
//vector containing coefficients for interpolation
for (int i = 0; i < 4; ++i)
vector1.push_back(vector<double>(nn - 1));
for (int ii = 0; ii < nn - 1; ii++)
{
vector1[ii][0] = ...;
}
Unsure if it is what you want, but assign could be interesting :
vector<vector<double>> vector1; // initialises an empty vector
// later in the code :
vector<double> v(nn -1, 0.); // creates a local vector of size 100 initialized with 0.
vector1.assign(4, v); // vector1 is now a vector of 4 vectors of 100 double (currently all 0.)

Dynamically allocating 2D int array

Can someone please point out what I am doing wrong in the following code?
int* a = NULL;
int* b = NULL;
a = new int[map->mapSize.width];
b = new int[map->mapSize.height];
layer->tileGids = new int[a][b];
Here's what the code uses:
typedef struct _size {
int width, height;
} size;
class Map {
size mapSize;
}
class Layer {
int * tileGids;
}
EDIT: Compiler-Errors (in line 6 of the first bit of code):
error: expression in new-declarator must have integral or enumeration type|
error: 'b' cannot appear in a constant-expression|
Solution:
I have decided to accept lightalchemist's answer. In essence, what works for me is use a vector instead of the array. Vector manages the memory for you and hence is a lot easier to deal with.
You can't pass a pointer for initializing the size of an array. Others have now mentioned this.
This post (it's not mine) seems like it might help you: http://eli.thegreenplace.net/2003/07/23/allocating-multi-dimensional-arrays-in-c/
You should also consider doing the allocation in the class Layer's constructor and then deleting the memory in it's destructor (i.e. RAII - resource acquisition is initialization). This is considered good style.
Finally, you might consider using continuous memory and a custom indexing scheme, which you could easily use Layer to encapsulate. This of course depends upon how big things will get. The bigger they get the better the case for continuous memory becomes.
This should give you a flavor.
#include <iostream>
#include <cstdlib>
int main()
{
const size_t ROWS = 5;
const size_t COLS = 2;
const size_t size = ROWS*COLS;
int* arr = new int[size];
int i = 0;
for ( size_t r = 0 ; r < ROWS; ++r )
{
for (size_t c = 0; c < COLS; ++c )
{
arr[r*COLS+c] = i++;
}
}
for ( int j = 0; j < i; ++j)
{
std::cout << arr[j] << std::endl;
}
delete [] arr;
}
Firstly, your variables "a" and "b" are pointers. Your code:
layer->tileGids = new int[a][b]
is the root cause of the problem.
I'm trying to guess your intention here and I think what you are trying to do is make layer.tileGids a 2 dimension array to reference a "grid" of size (mapSize.Width, mapSize.height) so that you can refer to each "cell" in the grid using layer.tileGids[x][y].
If you are indeed trying to create a 2 dimension array, there are 2 methods to do it.
Method 1:
class Layer {
int ** tileGids; // NOTE the "**" to indicate tileGids is a pointer to pointer i.e. 2D array.
}
To initialize it:
int width = map->mapSize.width;
int height = map->mapSize.height;
layer.tileGids = new int*[width]; // NOTE the "int*" to indicate tileGids is a new array of pointers to int.
for (int i = 0; i < width; i++) // Initialize each element in layer.tileGids[] to be a pointer to int.
{
layer.tileGids[i] = new int[height];
}
Now you can access the items in layer.tileGids using:
int value = layer.tileGids[x][y] // where 0 <= x < width and 0 <= y < height
To deallocate this data structure, similar to how you allocate it, you need to deallocate each dynamically allocated array in each "row":
for (int i = 0; i < width; i++)
{
delete [] layer.tileGids[i]; // Deallocate each row.
}
delete [] layer.tileGids; // Deallocate "array" to the pointers itself.
Method 2:
Now another easier, less messy method (avoid pointers) is to use the C++ vector class. You need to make the following changes:
#include <vector>
class Layer {
vector<vector<int> > tileGids; // Note the space at "<int> >".
}
To initialize:
int width = map->mapSize.width;
int height = map->mapSize.height;
layer.tileGids = vector<vector<int> >(width, vector<int>(height, 0)); // Initialize all entries to 0.
To access the elements:
int value = layer.tileGids[x][y]; // Where 0 <= x < width and 0 <= y < height
Note that for the second method using vectors, you do not have to do any memory cleanup as is required in the first method because the vector will automatically take care of it. However, because a vector can grow dynamically i.e. you can add items to it, you lose the safety of having a fixed size array i.e. someone could accidentally increase the size of your grid if you use the vector method but if he tries to do that when you intialized it using the first method above an error will occur and you will immediately know that something is wrong.
Can someone please point out what I am doing wrong in the following code?
A lot. You're allocating two single arrays (a "row array" and a "column array", not what you need), and then you try to do something strange.
Generally you can't (strictly speaking) dynamically allocate a 2D array in C++ (because the type system would still need the type, along with the dimensions, to be known at compile time). You can emulate it with an array of arrays or so, but the best way is to allocate an 1D array:
int width=5;
std::vector<int> tab(width*height);
and then access the element by calculating the coordinates manually:
// access the element (1,2)
tab[1 + 2*width] = 10;
This way you're essentially interpreting a 1D array as a 2D array (with performance equal to static 2D arrays).
Then it's best to wrap the indexing with a class for convenience; boost::multi_array also has this done for you already.
a and b are int* here:
layer->tileGids = new int[a][b];
Perhaps you meant to say this?
layer->tileGids = new int[*a][*b];