vector inside a map is clear safe? - c++

Just a quick question, if you have say:
using namespace std;
map< int, vector< string > > map1;
or maybe even:
map< int, map< int, vector< string > > > map2;
and just so you get the right idea:
map< int, map< int, map< int, vector< string > > > > map3;
if I do just:
map1.clear();
map2.clear();
map3.clear();
Is it safe in that it will empty everything in the map and its nested maps, vectors, lists, etc.?
Note:
I know if you use pointers you need to manually go through and delete or if the map goes out of scope it should be fine too I'm only particularly interested in this case when in scope and on the stack.

Yes, a map will destruct all components.
If its components are STL containers, their destructors will clear the containers.
Read more about STL containers notably about destructor of std::map

Yes this is perfectly safe. STL containers take care of memory management.
However, if you store pointers to objects which you allocated youself, you also have to delete them yourself:
std::vector<MyClass*> vec;
vec.push_back(new MyClass());
vec.clear(); // you get a memory leak here because you did not delete the object you allocated.

Related

Clearing a complex map

I have a map in C++ as:
std::map<std::pair<std::string, std::string>, std::unique_ptr<T>> my_map;
Will using my_map.clear cause memory leak issue ?

Making an array of pairs of vectors

I'm trying to make an array of pairs of vectors, and in the vectors is another pair of int and float. Here is the code to help explain: pair<vector<pair<int,float> >, vector<float> >[numNodes];
At first I just had an array of a vector of pairs, but now that I changed it to an array of pairs I'm being thrown errors. I think the errors have to do with the placement of make_pair but I'm not sure.
Here is my code, but first, I little more information on what exactly I'm trying to do with the code. I'm working on a school assignment where the goal is to read in a three files of a graph and store it as an adjacency matrix and adjacency list. Right now I'm working on the list. One file has just the connections, another has the weights of the connections, and the last file has the position values of each node. Then I will search the graphs with different search algorithms. The array of vectors was the adjacency list and all the other data types involved in the pair<vector<pair<int,float> >, vector<float> >[numNodes]; were an attempt to store these variables in the list. I know another way of doing this would be to have a Node object with member variables where I can save the nodeID and position values, but I don't know exactly how this would work in terms of adding it into the list. Also would there be advantages to doing this rather than having everything stored in the list?
class AdjacencyList{
public:
pair<vector<pair<int,float> >, vector<float> > *adjList;
int numNodes;
AdjacencyList(int numNodes){//constructor
this->numNodes = numNodes;
adjList = new pair<vector<pair<int,float> >, vector<float> >[numNodes];
}
void addEdge(int sourceNode, int destNode, float weight, vector<float> posVals){
make_pair(adjList[sourceNode].push_back(make_pair(destNode, weight)), posVals);
}
}
And here is the error I'm being thrown:
main.cpp:71:39: error: no member named 'push_back' in
'std::__1::pair<std::__1::vector<std::__1::pair<int, float>,
std::__1::allocator<std::__1::pair<int, float> > >,
std::__1::vector<float, std::__1::allocator<float> > >'
make_pair(adjList[sourceNode].push_back(make_pair(destNode, weig...
Another Error I'm getting after changing the array of vectors to an array of pairs is this:
no member named 'size' in
'std::__1::pair<std::__1::vector<std::__1::pair<int, float>,
std::__1::allocator<std::__1::pair<int, float> > >,
std::__1::vector<float, std::__1::allocator<float> > >'
return adjList->size();
This size function was working before the change, which makes me think these errors are happening because its recognizing it as a pair now instead of an array. Any ideas on how to fix this?
I have no idea what vector of pairs of vectors of pairs of ints and floats and vectors of floats could possibly in any possible way represent, but anyway you could just assign to the pairs of vectors you want to assign to:
#include <vector>
class AdjacencyList{
public:
std::vector<
std::pair<
std::vector<std::pair<int,float>>,
std::vector<float>
>
> adjList;
int numNodes;
AdjacencyList(int numNodes) :
numNodes(numNodes),
// construct the vector with numNodes default-constructred elements
adjList(numNodes) {
}
void addEdge(int sourceNode, int destNode, float weight, std::vector<float> posVals){
// prefer at() instead of [] for error checking
adjList.at(sourceNode) = std::make_pair(
std::vector<std::pair<int, float>>{
// vector of pairs?? anyway:
std::make_pair(
destNode, weight
)
},
posVals
);
}
};
Do not use raw pointers - use std::vector for managing dynamic array. Your code leaks memory allocated by new.
In the first error thrown, the compiler is complaining about a missing method push_back being called. If you look at it, this makes sense because you are trying to call push_back from a pair variable (which does not have implemented any push_back method). And a similar thing goes with the second error: size() is a valid method for the vector class, but here you are calling it from a pointer pointing to an array (check this question for more info).
Instead of an array of pairs, you could use a vector of pairs, or even a set of pairs:
class AdjacencyList{
public:
vector<pair<vector<pair<int,float> >, vector<float> > > adjList;
int numNodes;
AdjacencyList(int numNodes){//constructor
this->numNodes = numNodes;
// no need to initialize the vector
//adjList = new pair<vector<pair<int,float> >, vector<float> >[numNodes];
}
void addEdge(int sourceNode, int destNode, float weight, vector<float> posVals){
// add the new pair <int, float> to the existent vector for this source node
adjList[sourceNode].first.push_back(make_pair(destNode, weight));
// define second value of the outer pair as the parameter variable posVals?
adjList[sourceNode].second = posVals;
// or you wanted to do this? I don't think so :S
make_pair(adjList[sourceNode].first, posVals);
}
}
You could do the same using an outer set instead of vector, and then you would need to change the push_back(...) for insert(...), so that you obtain the benefits of sets of pairs as well.
Actually, if you need to do it using outer arrays, then your code would be fine but changing your AddEdge function to the one proposed above.
I don't really know which is the desired performance of the code, but if you provide more information about it I might be able to help a bit more.
I think you have some inconsistencies in the type declared and the type being added.
You have declared an array (now does not matter whether it is an array, vector, or set) of pairs of vectors. Whereas on your addEdge function you are creating a pair of None (push_back returns None) and vector. The push_back on its side is adding the pair <int, float> of the first vector of the outer pair to you differently variable defined above.

Do i need to clear map after assign new map?

Here is an example :
pair< map<int, string>, map<int, string> > test;
test = data;
So do i need to call clear method before assign? Like this :
pair< map<int, string>, map<int, string> > test;
test.first.clear();
test.second.clear();
test = data;
Or first example is correct without memory leaks?
http://www.cplusplus.com/reference/map/map/map/
Map constructor - constructs empty container with no elements.
Pair -Constructs a pair object with its elements value-initialized.
So, my guess is that there is no memory leak, plus you are not allocating any memory there so.

How to effectively reuse mapped value

The program has the following input data:
std::map<std::string, std::vector<int> >
Now I need to convert this data structure into the following:
std::map<int, std::vector<int> >
Fo example:
"key1" => 1
"key2" => 20
etc.
Only the key type is changed, the mapped value is unchanged.
The question is that how I can reuse the mapped key std::vector<int> effectively so that the mappped value is not copied since there is no need to do so.
Here are two ideas that come to my mind:
////////////////////////////////////////////////////
Solution 1>
redefine the interface
from
std::map<int, std::vector<int> >
to
std::map<int, std::vector<int>* >
////////////////////////////////////////////////////
Solution 2>
redefine the interface
from:
std::map<std::string, std::vector<int> >
std::map<int, std::vector<int> >
to:
std::map<std::string, boost::shared_ptr<std::vector<int>> >
std::map<int, boost::shared_ptr<std::vector<int>> >
In both cases, the cost of the copy is simply a copy of a pointer.
Any comment is appreciated
C++11 provides move-operations to move one object to another without copying. VS 2010 should have the necessary machinery implemented. With this, assuming you have a mapping for old to new keys, you can remap the data like this:
std::map<std::string, std::vector> m1;
std::map<int, std::vector> m2;
std::map<std::string, int> keymap;
for (auto i=m1.begin(); i != m1.end(); ++i)
{
m2[keymap[i->first]] = std::move(i->second);
}
Now, all vectors have been moved to a new map leaving the map m1 in an undefined, but destructible state.
If C++11 (as available in VS2010) is not an option, swap the new map with the old one:
std::map<std::string, std::vector> m1;
std::map<int, std::vector> m2;
std::map<std::string, int> keymap;
for (std::map<std::string, std::vector>::iterator i=m1.begin(); i != m1.end(); ++i)
{
m2[keymap[i->first]].swap(i->second);
}

C++ 5 dimensional vector?

I am trying to make a 5 dimensional vector and I can’t seem to get it to work.
I know if I need to write a 3 dimensional vector, I could write it in the following way:
vector< vector< vector<string> > > block(27, vector< vector<string> > (27, vector<string>(27)));
Then I call it: block[x][y][z] = “hello”;
I wrote the 5 dimensional vector in the following way and it gives me error.
vector< vector< vector< vector< vector<string> > > > > block(27, vector< vector< vector< vector<string> > > >(27, vector< vector< vector<string> > >(27, vector< vector<string> >(27, vector<string>(27)))));
Can you please tell me how to write a 5 dimensional vector in the right way?
Thanks a lot.
The final vector in your 5 dimensional array does not have a type that it is an array of.
vector< vector< vector< vector< vector > > > >
^^
Here. What is the base vector a vector off?
To make things easy to read a couple of typedefs would be nice:
typedef std::vector<std::string> Dim1;
typedef std::vector<Dim1> Dim2;
typedef std::vector<Dim2> Dim3;
typedef std::vector<Dim3> Dim4;
typedef std::vector<Dim4> Dim5;
Dim5 block(27, Dim4(27, Dim3(27, Dim2(27, Dim1(27)))));
Consider using the Boost Multidimensional Array Library for higher dimensional arrays.
http://www.boost.org/doc/libs/1_43_0/libs/multi_array/doc/user.html
"Boost MultiArray is a more efficient and convenient way to express N-dimensional arrays than existing alternatives (especially the std::vector> formulation of N-dimensional arrays). The arrays provided by the library may be accessed using the familiar syntax of native C++ arrays. Additional features, such as resizing, reshaping, and creating views are available (and described below)."
But you should stop and think if a dictionary would work better. If the data is sparse you'll save a ton of memory.
Create a key using the 5 dimensions, and create only the members you need.