alias used not modifying the actual contents of STL container - c++

I am unable to understand the following behaviour. When I use currPMap to modify the value, the value at the actual location is not modified. Why is that so.
I checked with the reference the operator[] and at() return reference and so this should have worked.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
typedef map<int, int> intMap;
typedef map<int, int>::iterator mapIt;
int main(void) {
vector< map<int, intMap > > b(2);
int curr=0, next=1;
map<int, intMap> currPMap = b.at(curr);
(currPMap[4])[2] = 3; //modified by currPMap.
cout<<((b.at(curr))[4])[2]<<endl;
((b.at(curr))[4])[2] = 3; //modified using the actual vector.
cout<<((b.at(curr))[4])[2]<<endl;
}
Output:
0
3
P.S.: I know what I am doing here can be achieved by many other ways in this setting, but this is not the actual program. This is just the explicit version of the problem that I am facing with my code. I would be grateful if someone answers what is wrong in this method.

Because you are getting a copy of a map here, not an alias:
map<int, intMap> currPMap = b.at(curr); // currMap is a copy of b[0]
You then modify the copy, not the map stored in the vector.
What you need is a reference:
map<int, intMap>& currPMap = b.at(curr); // currMap refers to b[0]

map<int, intMap> currPMap = b.at(curr);
That's not an alias (aka reference); that's a copy. If you want a reference, you need to declare it thusly:
map<int, intMap> & currPMap = b.at(curr);
^
Beware that the reference may be invalidated if you add or remove elements to the vector, since vectors need to move their elements to maintain a contiguous array.

Related

How to insert single existing pair into a map

I have an already defined pair, and I want to insert it into a map. What are the correct way/s of doing that?
I tried two. One works. The other (which I mean to use, since it is more compact and clear) does not. There are no runtime errors, but it simply does not work (I checked this with the return value of insert, whose second member is False).
I guess the way to fix the second form is simple, but I could not find it.
This is what I have:
using namespace std;
typedef pair<string, char> pair_t;
typedef map<pair_t::first_type, pair_t::second_type> map_t;
typedef pair<map_t::iterator,bool> retval_insert_t;
int main(void) {
pair_t p2;
p2 = make_pair("Fer", 'C');
map_t grade_list;
grade_list[ "Jorge" ] = 'A';
grade_list.insert(make_pair("Alba", 'D'));
grade_list.insert(pair_t("Susi", 'C'));
grade_list.insert(make_pair(p2.first, p2.second)); // This works
grade_list.insert(p2); // This does not work
return 0;
}

c++ can I new a vector like this in my code into a hashmap

// father is an array of integers, irrelevant to the actual question
vector<pair<int,int>> edges = {
{0, 2},
{2, 3},
{1, 4},
{1, 5}
};
unordered_map<int, vector<pair<int,int>> edges_map_by_component;
for(auto edge: edges){
if(edges_map.find(father[edge.first]) == edges_map_by_component_map.end()){
// ---> my question is, is the following line valid?
edges_map_by_component.emplace(father[edge.first] , new vector<pair<int,int>>());
edges_map[father[edge.first]].push_back(make_pair (edge.first,edge.second));
}
}
In C++,
Can I add a vector object to the hashmap using new like this?
Is that line valid?
If yes, do I need to specify size for vectorif I instantiate it
inside the map?
Edit:
You've said I should not use new here, but seems like simply removing new is not working either. what should I do here. Basically my logic is, if the hashmap does not contain a particular key, I will create a vector of pair<int, int> for it, associate it with that key, and push_back() some pairs into the vector.
You have either a typo or a mistake in your code:
unordered_map<int, vector<pair<int,int>> edges_map_by_component;
// ^^
Should be (given you're using C++11 where you don't need to put spaces between subsequent closing template braces):
unordered_map<int, vector<pair<int,int>>> edges_map_by_component;
// ^^^
Other than that, indeed, remove new, since the second parameter of your map is vector<pair<int, int>>, not a pointer to that. That way it works fine:
#include <iostream>
#include <vector>
#include <unordered_map>
int main(void)
{
std::unordered_map<int, std::vector<std::pair<int,int> > > mymap;
mymap.emplace(5, std::vector<std::pair<int,int> >());
mymap[5].push_back({5, 7});
const std::pair<int, int> p = mymap[5].back();
std::cout << p.first << p.second;
}
The types are shown explicitly for clarity sake. A shorter way to write it would be something along the lines of:
mymap.emplace(5, decltype(mymap)::mapped_type());
One more note is that the emplace operation uses move semantics, so there is no additional copying going on, and you can construct a vector beforehand, fill it with values, and pass to emplace().
Yes usually. No not like you did because you are using the wrong type. What you are inserting here is a pointer to a vector which you haven't declared in your template parameters. You either need to change the template parameter to unsorted_map<int, vector<pair<int,int> >* > or you remove the new. This depends on how you want to use this structure later.

set/access jagged map values made with map<string, boost::any>

I've been shown how to create a jagged multidimensional std::map by using boost::any.
However, I'm having trouble setting the values like in this answer.
When I use
accounts["bank"]["cash"] = 100;
gcc gives this error
error: no match for ‘operator[]’ in ‘accounts.std::map<_Key, _Tp, _Compare,
_Alloc>::operator[]<std::basic_string<char>, boost::any,
std::less<std::basic_string<char> >, std::allocator<std::pair<const
std::basic_string<char>, boost::any> > >((* & std::basic_string<char>(((const
char*)"bank"), (*(const std::allocator<char>*)(& std::allocator<char>())))))["cash"]’
How can a jagged multidimensional map created with boost::any be accessed? (If there is a better technique to do this, please show me. I only care about what works and is quick to write.)
multidimensional declaration
std::map<std::string, boost::any> accounts;
accounts["bank"] = std::map<std::string, boost::any>();
accounts["bank"]["cash"] = 100;
json-spirit
I gave up and tried to use json-spirit's mObject instead since all of this seems already built in.
Funny thing is is that with the exact same notation, I get the exact same error.
std::map<std::string, boost::any> accounts;
accounts["bank"] = std::map<std::string, boost::any>();
accounts["bank"]["cash"] = 100;
Of course this cause compile time error, you put to boost::any std::map,
but compiler have no idea about this. accounts["bank"] has "boost::any" type,
and boost::any have no
int& operator[](const char *)
Read how boost::any works: http://www.boost.org/doc/libs/1_54_0/doc/html/any/s02.html
Fix is trivial:
#include <boost/any.hpp>
#include <map>
#include <string>
int main()
{
std::map<std::string, boost::any> accounts;
accounts["cash"] = 100;
accounts["bank"] = std::map<std::string, boost::any>();
boost::any_cast<std::map<std::string, boost::any> &>(accounts["bank"])["cash"] = 100;
}
How did you define your accounts map? As boris said, you need to nest two maps together in order to do what you want.
Replace the type string with boost::any
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
map<string, map<string, string>> accounts;
accounts["bank"]["cash"] = "infinity";
cout << accounts["bank"]["cash"];
return 0;
}
How does this work?
Maps are key and value pairs.
accounts["bank"] returns the value of the outermost map, which corresponds to
map<string, **map<string, string>**>
accounts["bank"]["cash"] returns the value of the innermost map, which corresponds to
map<string, map<string, **string**>>
Defining a 1 dimensional map does not allow you to do what you want, but 2 dimensional maps do.

Insert vector for value in map in C++

I am stuck on trying to figure out how to insert a vector for a value in a map. For example:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
int main()
{
map <int, vector<int> > mymap;
mymap.insert(pair<int, vector<int> > (10, #put something here#));
return 0;
}
I don't know what syntax to use insert a vector for value. I tried {1,2}, but that failed. What syntax should I use?
Everything works if I declare a vector in advance and give it a name, but I don't want to do that, as I want to have a map with a lot of vectors.
Thank You in Advance
If you want an empty vector you could do:
mymap.insert(pair<int,vector<int> >(10, vector<int>()));
You could then add whatever elements you want with something like:
mymap[10].push_back(1);
mymap[10].push_back(2);
Edit: Removed incorrect assertion that the vectors would be copied if/when the map grows. As the commenters pointed out, this is not true for std::map, which is node-based.
Basically your question is not about inserting std::vector into a std::map. Your question is how can you easily create an anonymous std::vector with arbitrary initial element values.
In ISO C++03, you can't. C++11 allows using initialization lists for this, however.
If you are stuck with a C++03 compiler, you possibly could create a helper function to return a vector with specified elements:
std::vector<int> make_vector(int a, int b)
{
std::vector<int> v;
v.push_back(a);
v.push_back(b);
return v;
}
If the vectors you're inserting are of different sizes, you could use a variadic function, although doing so would require that you either pass along the number of elements or have a reserved sentinel value.
If you are using C++11 you can use vector's initialization list constructor (the last constructor in that list) which would look like this:
mymap.insert(pair<int, vector<int> > (10, {1, 2, 3}));
If you can only use C++03, vector has a constructor that takes a size and a default value for each element that might be enough for you. Otherwise you will have to construct the vector and then insert it. If you want to avoid an unnessicary copy of the vector when inserting you could swap it in like so:
vector<int> myvec;
myvec.push_back(1);
myvec.push_back(2);
mymap[10].swap(myvec);
This way the vector won't need to be copied. You'll get an extra vector default construction but that's not very expensive.
#put something here# = vector<int>{1,2}
I'm surprised though that {1,2} didn't work. Are you not using a C++11 compiler? If not then you can only create the vector with default constructor there (no values), or fill it with values first and stick it in.
This should work in C++2003 compilers.
#include <iostream>
#include <vector>
#include <map>
#include <cassert>
using namespace std;
std::vector<int> make_vector(int a, int b) {
std::vector<int> result;
result.push_back(a);
result.push_back(b);
return result;
}
int main()
{
map <int, vector<int> > mymap;
mymap.insert(make_pair(10, make_vector(1,2)));
// Or, alternatively:
// mymap[10] = make_vector(1,2);
assert(mymap[10][0] == 1);
assert(mymap[10][1] == 2);
return 0;
}
C++03 does not have initializer lists, which can be a pain to initialize collections.
If you cannot upgrade to a more modern version of the compiler, you can always use the Boost.Assignment library. It has a list_of function precisely for this.
#put something here# -> boost::assign::list_of(1)(2)

Pointer to a map

If I define a pointer-to-map like this:
map<int, string>* mappings;
mappings is a pointer. How should I use this pointer to operate the map?
Use the pointer just like you use any other pointer: dereference it to get to the object to which it points.
typedef std::map<int, string>::iterator it_t;
it_t it1 = mappings->begin(); // (1)
it_t it2 = (*mappings).begin(); // (2)
string str = (*mappings)[0]; // (3)
Remember that a->b is — mostly — equivalent to (*a).b, then have fun!
(Though this equivalence doesn't hold for access-by-index like (*a)[b], for which you may not use the -> syntax.)
Not much difference except that you have to use -> for accessing the map members. i.e.
mapping->begin() or mapping->end()
If you don't feel comfortable with that then you can assign a reference to that and use it as in the natural way:
map<int, string> &myMap = *mappings; // 'myMap' works as an alias
^^^^^^^^
Use myMap as you generally use it. i.e.
myMap[2] = "2";
myMap.begin() or myMap.end();
For instance:
#include <map>
#include <string>
#include <iostream>
int main() {
std::map<int, std::string> * mapping = new std::map<int, std::string>();
(*mapping)[1] = "test";
std::cout << (*mapping)[1] <<std::endl;
}
With the introduction of "at" function in c++ 11, you can use mappings->at(key) instead of (*mapping)[key].
Keep in mind that this api will throw out_of_range exception if the key is not already available in the map.
another nice way of using pointers, which I like is calling mappings->(and the function you want to call)
Well, STL is designed to reduce the complexity of pointer handling..so better approach is to use stl::iterator.. try to avoid pointers :-/