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.
Related
so I'm creating a class that implements an adjacency list. Currently in my class definition I initialized two vectors:
vector<vector<int>> adjList;
vector<int> neighbors;
and I declared two functions that I plan to use to make it:
bool constructAdjList();
bool insertIntoAdjList(int, int);
It's getting difficult wrapping my head around 2D vectors. I understand that it is essentially a vector of vectors, but I'm confused about how to insert a new value into one of the "subvectors". For example, I am able to create an adjacency list in createAdjList that is empty with the following loop:
for (int i = 0; i < numOfValues; i++){
neighbors.push_back(0);
adjList.push_back(neighbors);
neighbors.clear();
}
But how can I say, push_back the value 5 to the 4th vector in adjList, which would be represented in my insertIntoAdjList function as
insertIntoAdjList(4, 5);
I know I can access a specific value in a 2D vector by saying adjList[4][1], but how can I push one onto it?
Thanks!
To push on the vector that is an element of another vector, you simply do this
adjList[x].push_back();
If initially you do not have any values in the vector -
You can push values into one vector and then push this vector into the 2D vector.
For example:
vector< vector<int> > vt1;
vector<int> vt2;
vt2.push_back(value);
vt1.push_back(vt2);
If your vector is already populated then -
vt1[index].push_back(value);
A couple of notes here.
Your loop can be significantly shortened just be using the constructors of your two members:
vector<int> neighbors(1, 0); // set to length 1, value is zero
vector<vector<int>> adjList(numOfValues,neighbors); // "outer" vector is numOfValues long
. // each row is a *COPY* of neighbor
If you can't do this at construction time (maybe numOfValues isn't known yet), then there's still a better loop phrasing we can use:
// neighbors object can be reused
neighbors.clear(0);
neighbors.push_back(0);
adjList.reserve(numOfValues); // reserving memory ahead of time will prevent allocations
for (int i = 0; i < numOfValues; i++){
adjList.push_back(neighbors); // push_back is by *COPY*
}
In your example, by using clear and push_back to essentially build the same vector every loop iteration, you are risking an allocation and deallocation each iteration. In practice, most implementations won't do this, but if we can both shorten and potentially make things more efficient, we may as well.
Lastly, if the number of neighbors is relatively small and similar row to row (for instance a finite elements code with tetrahedral elements, where each element connects to ~5 others), then as others have suggested you may be better off with a different structure than vector-of-vector. For instance, a single vector that is logically organized such that a new "row" begins every N elements.
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];
I'm building a CSVParser Library (using similar to Excel OLE objects), to be implemented using Vectors
the cell array is saved as a multi dimension string array in the main class CCSVParser
static vector< vector< string> > CellArray;
and another pointer array inside the CRange Class
vector< vector< string> >* RangeCells;
Edit : the purpose of using a pointer array is to save allocated space, since the library may handle large amount of data
inside the GetItem method of CRows class , i need to return a Range object with its pointer array pointing to the addressed row of the main CellArray
CRange* CRows::GetItem(int idxRow)
{
CRange* retRange = new CRange ;
retRange->RangeCells = (vector< vector<string> >*)&CCSVParser::CellArray[idxRow] ;
return retRange;
}
the vector array pointer works fine when pointing to the whole array
retRange->RangeCells = (vector< vector<string> >*)&CCSVParser::CellArray ;
but fails addressing just a row in the CellArray
Note : RangeCells pointer array needs to be multi-dimensional, since in other operations it may return a set of rows
Any ideas how to fulfill this???
Thanks in advance
If CellArray is a vector of vectors (of strings), then CellArray[i] is a vector (of string). However, you try to assigning its address to a pointer to a vector of vectors (of strings) and that is not possible.
The address of a vector is not the same as the address of a vectors of vectors.
RangeCells should be declared as
vector<string> *RangeCells;
I'm guessing it will work much better.
Hi I have a problem where at compile time, I don't know how many vectors in my program are needed. The number required depends on a data set given at run-time, which will results in the range of vectors needed to be from 1 to N.
So if the data set requires ten vectors, it will create vec1,vec2,......vecN
How can i dynamically create the vectors so that they all have a different name?
I would then need to call each array separately. Presumably
I could just use strings and a few loops for this.
You can't do that directly. However, you could use a map to store a vector name, and the vector itself:
map<string, vector<int> > myMap;
You can add elements simply like this (if the element with such key doesn't exist yet):
vector<int> vec;
myMap["vec"] = vec;
If you'll do it with a key that already exists, the value will be replaced. For example:
vector<int> vec;
vector<int> vec1;
myMap["vec"] = vec;
myMap["vec"] = vec1;//now myMap["vec"] holds the vec1 vector
You can also easlly access elements like this:
myMap["vec"]//this will access the vector with the key "vec1"
You can create a vector to contain your vectors:
std::vector<std::vector<int>> my_vector_of_vectors;
// Add a vector
my_vector_of_vectors.push_back(std::vector<int>{});
// Add a number to the inner vector
my_vector_of_vectors[0].push_back(1);
you have a vector of vectors, vec[0] to vec[n], each one containing the vector.
However, this works est if you know the number of vectors (eg 10). If you need to add new ones on-demand, then a list of vectors or a map might be a better option for you.
I am writing a friend recommendation algorithm and in a part I have to store 350 random friendship using the data type std::pair in C++. I basically use an adjacency list (implemented as vector of vectors). I create a vector that stores data type pair<int,int>. I select a random value from the adjacency list and select one of it's friends randomly, however, even though I'm quite sure that I push the data type as pair however I cannot iterate through it.
What could be the possible reason?
int FRIENDS_AND_UNFRIENDS_TO_STORE=350,randomNode=rand()%adjacencyList.size(),randomFriend;
vector< pair<int,int> >listForPR;
listForPR.resize(FRIENDS_AND_UNFRIENDS_TO_STORE*2);
for(int i=0;i<FRIENDS_AND_UNFRIENDS_TO_STORE;i++) {
while(adjacencyList[randomNode].size()<1)
randomNode=rand()%adjacencyList.size();
randomFriend=rand()%adjacencyList[randomNode].size();
listForPR.push_back(make_pair(randomNode,adjacencyList[randomNode][randomFriend]));
}
for(int i=0;i<350;i++)
cout<<"Node #"<<listForPR[i].first<<" & It's Friend: "<<listForPR[i].second<<endl;
Added this and !mysteriously solved the problem;
for(int i=0;i<FRIENDS_AND_UNFRIENDS_TO_STORE;i++) {
while(adjacencyList[randomNode].size()<1)
randomNode=rand()%adjacencyList.size();
randomFriend=rand()%adjacencyList[randomNode].size();
pair<int,int> temp=make_pair(randomNode,adjacencyList[randomNode][randomFriend]);//added
listForPR.push_back(temp);
}
Your vector contains 350/2 = 175 elements that you pushed in during the loop, but you are going through 350 elements when you iterate.
You shouldn't mix resize and push_back.
The first resize fills listForPR with 350 zeroed items.
Then push_back adds items to the end of the vector.
Deleting resize statement should fix the problem. Even better solution is to use reserve (it just prepares buffer in vector for insertion).