C++ Push back a vector into a vector - c++

This is the vector I created;
std::vector<std::vector<Vertex*>*> Vertices;
And I'm having trouble figuring out how to push back the std::vector<Vertex*> into the outer
vector.
So what im kind of trying to do is:
Vertices.push_back(new vector().push_back(new Vertex()));
but I'm not sure what the right way to do it is. Hope you people get the idea.

Although it is sometimes OK to make a vector of pointers (preferably, smart pointers), it is never a good idea to make a vector of pointers to vectors: this complicates your memory management for no good reason.
The best solution is to use a vector of vertex objects, like this:
std::vector<std::vector<Vertex> > vertices;
This would let you push back like this:
vector<Vertex> vv;
vv.push_back(Vertex(...));
vertices.push_back(vv);
If you want a vector of descendants of Vertex with polymorphic behavior, use a vector of vectors of pointers:
std::vector<std::vector<Vertex*> > vertices;
...
vector<Vertex*> vv;
vv.push_back(new Vertex(...));
vertices.push_back(vv);
Note that if you do this, you are on the hook for freeing the Vertex objects inside the vector. A better solution would be using smart pointers - say, unique_ptr, like this:
std::vector<std::vector<unique_ptr<Vertex> > > vertices;
unique_ptr would take care of freeing Vertex objects automatically.

You can't do it in a single line. But you can do it in 4;
std::vector<std::vector<Vertex*>*> Vertices;
std::vector<Vertex*> * vec = new std::vector<Vertex*>;
vec.push_back(new Vertex()); // fill the inner vector as many times as you need
Vertices.push_back(vec);
But why you would want to do that? You will leak memory if you won't call delete for each element of the outer vector, but before doing that you will need to call delete on every Vertex* in inside vectors.
Edit: for a better way of storing Vertex without leaking memory look at dasblinkenlight's answer.

It is doable. For example, try:
std::vector<std::vector<Vertex*>> Vertices;
Vertices.push_pack(std::vector<Vertex*>());
Vertices.back().push_back(new Vertex[8]);
Following this code, you do not need to use any extra memory.
To access or modify the element located in the i'th member of first vector, and j'th member of the second vector, and the 6th member of the array, you can use:
Vertices.at(i).at(j)[6];

Related

create vector with new elements

so I have the following
vector<vector< tuple<string, double>*>*>* graph;
a 2d vector, with a tuple of string and double.
I want to initialize the graph(2d vector) with a certain size and
a new vector< tuple<string, double>*>, in each of the element of the big (outside)vector
and I used the following line
graph = new vector<vector<tuple<string, double>*>*>(67, new vector< tuple<string,double>*>());
This thing works but when I tried to free it I found out that all new vectors I created are of the
same vector.
meaning, all the elements point to the same vector. I get why this is happening but
is there a way of initialize all the vectors without having to do the for loop, ie
for(int i....)
graph->push_back(new vector< tuple<string,double>*>);
Problem summary:
In the line
graph = new vector<vector<tuple<string, double>*>*>(67, new vector< tuple<string,double>*>());
constructor 3 of std::vector is used (reference)
This will evaluate new vector<tuple<string,double>*>() once, then create a vector with 67 copies of this pointer.
Solution:
Don't use pointers unless you have a really good reason to do so. Use
vector<vector<tuple<string, double>>> graph;
then you could simply do
graph.resize(67);
to insert 67 default constructed values. No pointers needed.
Maybe you are used to languages where new is frequently used, but you shouldn't do that in C++. std::vector and std::string are fairly small objects that manage an underlying dynamic array. Creating pointers to them is usually not what you want and might also decrease performance.

Does an array of vectors form a 2D vector?

Does the following statements form a 2D vector?
Also mention the dimensions of the vector if it does. Is there another way of declaring a global 2D vector?
Statements:
vector<int> *adj;
adj = new vector<int>[number_of_nodes];
The above statements have been used for declaration of a global adjacency matrix for a graph.
It seems the question isn't clear to much of you. I want to declare a global adjacency list using vectors such that I can use direct addition of edges in graph like v[a].push_back(b). For that, I have to specify first dimension of vector while declaring which I don't have until the main is executed.
No, but it gives similar behaviour. So what you have created is a pointer to an array of vectors. So you will end up with this:
adj[0] = []
adj[1] = []
...
adj[number_nodes] = []
and doing a push_back is a legitimate way to add to the vectors:
adj[0].push_back(some_num) --> adj[0] = [some_num]
But this is a terrible way to approach this! Why?
You are using raw memory that you will have to manage and make sure you delete.
You cant use any of the awesome std::vector functionality on the first dimension of the matrix.
There is no good way to figure out the size of the vector unless you know about the variable number_of_nodes.
... A long list, but you get it.
You can already see that a std::vector can be used as a 1D matrix. So use 2 vectors:
std::vector<std::vector<int>> Matrix2D;
If you need an initial size in some dimension then you can do this:
std::vector<std::vector<int>> Matrix2D(number_of_nodes, std::vector<int>());
Or this:
Matrix2D.resize(number_of_nodes);
Or if that size is fixed at compile time then you could even do this:
const int number_of_nodes = 10;
std::array<std::vector<int>, number_of_nodes> Matrix2D;
Or go extra big and get a library for Matrix use like Eigen.

C++ : Null pointers and structs

If I want to make a struct for representing an item to render on the screen, and contains:
A list of natives "renderables" (meshes, triangles, etc)
A pointer to others sub-structures
Does this:
struct RenderGroup {
std::vector<RenderGroup*> Children;
std::vector<Renderable> Renderables;
}
What is the best way to do this? And if I have no sub-structures, can I just put a null pointer in the vector ?
Edit : Bad tags
A std::vector is not fixed size, so if there are no elements in it, size will return 0 and empty will return true.
std::vector<int> v;
auto sz = v.size(); // sz has value 0
auto e = v.empty(); // true
v.push_back(42);
sz = v.size(); // 1
e = v.emi empty(); // false
You can also remove elements (the vector moves all the followingv elements down to fill the gap)
std::vector<int> v { 1, 2, 3 };
auto it = v.find(2);
if (it != v.end())
v.erase(it); // v now contains 1, 3
So, in theory, no you don't need to put nullptrs in your vector. This assumes you've designed your application in a way that doesn't require a certain population size in your vector; if so, vector might not be the right container. Consider std::array.
There is a problem with your renderables vector, though: the vector stores instances of Renderable. The elements I'm the vector are exactly the size of a Renderable. So if you try and store a derived class, e.g Mesh, you will lose the derived classes extra fields.
This is called slicing. https://en.m.wikipedia.org/wiki/Object_slicing
You'll need to store pointers or references to the instances of the objects. Which depends on lifetime and ownership of the instances.
If your vector owns the remediables, you could use std::vector<std::unique_pre<Remediable>>.
If you are being given the instances from your caller, perhaps std::shared_ptr.
There's no need to put arbitrary "nothing" records in a std::vector, this isn't like a variable-length C-style array where you must terminate with some kind of delimiter. Just leave it empty.
In general practice you want to avoid putting NULL into lists like this where something might iterate over the contents and re-reference that pointer, causing a crash.
If RenderGroup is a base class and your Children vector is storing arbitrary children classes of RenderGroup then this approach is "fine" (though smart pointers would probably be preferred).
However, as tadman mentioned, if you're using pointers to represent the absense of a RenderGroup, you'll probably want to instead just remove the items in the vector when they are no longer needed.
See if this structure can help:
struct RenderGroup {
std::map<Renderable, std::vector<RenderGroup*>> Renderables;
}
List of child (RenderGroup) objects are mapped to Renderable object.

Use of pointer to vector which involved the use of 'new'

I would like to create a vector of pointers to struct
vector<myStruct*> vec
For elements in the vector, not all of them contain data. Some of them may point to NULL.
So, should I create space by new in each of the element first
for(int i = 0; vec.size() ;i++){
if (thisSpaceIsValid(i))
vec.at(i) = new myStruct;
else
vect.at(i) = NULL;
}
The problem comes:
-If I use new for each element, it would be very slow. How can I speed it up a bit? Is there a way the create all the spaces that I need , that automatically access the pointer of such space to the vector(vec here)?
-If later I use delete to free the memory, would the problem of speed still bother me?
If I use "new" for each element, it would be very slow. How can I speed it up a bit? Is there a way the create all the spaces that I need , that automatically access the pointer of such space to the vector("vec" here)?
You can do that.
Let's say the size of your vector is M and you only need N of those elements to have pointers to objects and other elements are null pointers. You can use:
myStruct* objects = new myStruct[N];
and then, use:
for(int i = 0, j = 0; vec.size(); i++)
{
if (thisSpaceIsValid(i))
{
if ( j == N )
{
// Error. Do something.
}
else
{
vec[i] = objects+j;
++j;
}
}
else
{
vect[i] = NULL;
}
}
You have to now make sure that you are able to keep track of the value of objeccts so you can safely deallocate the memory by using
delete [] objects;
PS
There might be a better and more elegant solution to your problem. It will be worth your while to spend a bit more time thinking over that.
EDIT:
After reading the question again, it seems I misunderstood the question. So here is an edited answer.
If you only need to execute the code during some kind of initialization phase, you can create all the instances of myStruct in an array and then just point to those from the vector as already proposed by R Sahu. Note that the solution requires you to create and delete all instances at the same time.
However, if you execute this code several times and/or don't know exactly how many myStruct instances you will need, you could overwrite new and delete for the struct and handle memory allocation yourself.
See Callling object constructor/destructor with a custom allocator for an example of this. See the answer by Jerry Coffin.
BTW - you don't need vec.at(i) as you are iterating from 0 to size. vec[i] is okay and should perform a better.
OLD ANSWER:
You can do
vector<myStruct*> vec(10000, nullptr);
to generate a vector with for instance 10000 elements all initialized to nullptr
After that you can fill the relevant elements with pointer to the struct.
For delete just
for (auto e : vec) delete e;
cause it is safe to do deleteon a nullptr
If you need a vector of pointers, and would like to avoid calling new, then firstly create a container of structs themselves, then assign pointers to the elements into your vec. Be careful with choosing the container of structs. If you use vector of structs, make sure to reserve all elements in advance, otherwise its elements may move to a different memory location when vector grows. Deque on the other hand guarantees its elements don't move.
Multiple small new and delete calls should be avoided if possible in c++ when performance matters a lot.
The more I think about it, the less I like #RSahu's solution. In particular, I feel memory management in this scenario would be a nightmare. Instead I suggest using a vector of unique_ptr's owning memory allocated via custom alloctor. I believe, sequential allocator would do.

pop-push element from std::vector and reuse elements

i have a project in c++03 that have a problem with data structure: i use vector instead of list even if i have to continuously pop_front-push_back. but for now it is ok because i need to rewrite too many code for now.
my approach is tuo have a buffer of last frame_size point always updated. so each frame i have to pop front and push back. (mayebe there is a name for this approach?)
so i use this code:
Point apoint; // allocate new point
apoint.x = xx;
apoint.y = yy;
int size = points.size()
if (size > frame_size) {
this->points.erase( points.begin() ); // pop_front
}
this->points.push_back(apoint);
i have some ready-to-use code for an object pool and so i thought: it is not a great optimization but i can store the front in the pool and so i can gain the allocation time of apoint.
ok this is not so useful and probably it make no sense but i ask just to educational curiosity: how can i do that?
how can i store the memory of erased element of a vector for reusing it? does this question make sense? if not, why?
.. because erase does not return the erased vector, it return:
A random access iterator pointing to the new location of the element
that followed the last element erased by the function call, which is
the vector end if the operation erased the last element in the
sequence.
i have some ready-to-use code for an object pool ... how can i do that?
Using a vector, you can't. A vector stores its elements in a contiguous array, so they can't be allocated one at a time, only in blocks of arbitrary size. Therefore, you can't use an object pool as an allocator for std::vector.
how can i store the memory of erased element of a vector for reusing it? does this question make sense? if not, why?
The vector already does that. Your call to erase moves all the elements down into the space vacated by the first element, leaving an empty space at the end to push the new element into.
As long as you use a vector, you can't avoid moving all the elements when you erase the first; if that is too inefficient, then use a deque (or possibly a list) instead.
I'm not sure to understand what you want to do, but this should be functionnally equivalent to what you wrote, without constructing a temporary Point instance:
// don't do this on an empty vector
assert (points.size() > 0);
// rotate elements in the vector, erasing the first element
// and duplicating the last one
copy (points.begin()+1, points.end(), points.begin());
// overwrite the last element with your new data
points.back().x = xx;
points.back().y = yy;
EDIT: As Mike Seymour noted in the comments, neither this solution nor the approach proposed in the question cause any new memory allocation.