Holding unordered_map element to a pointer/iterator - c++

Each time to find an element I use find and thus, I have a pointer returned to it (iterator would be better to describe it rather than pointer). But, in the case the element is not there, I go create it.
The problem is that after both cases I want to have something that will point to that element no matter if it existed or not (because I ensured that I created it). My solution is to use find (for the second time, which I guess is costly), but I think that there could be a unified way to hold a reference to the item without doing a second search (either by previous find or while creating the item).
Is this possible?

This is a common pattern -- you can use insert() which returns an iterator whether something was added or not:
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
int main()
{
std::unordered_map<int, string> m;
auto result = m.insert(std::make_pair(0, "Foo"));
if(result.second)
cout << "Inserted: " << result.first->first << " -> " << result.first->second << '\n';
result = m.insert(std::make_pair(0, "Bar"));
if(!result.second)
result.first->second = "Bar";
for(auto i : m)
cout << i.first << " -> " << i.second << '\n';
return 0;
}
Output:
Inserted: 0 -> Foo
0 -> Bar

Use std::unordered_map::insert.
It's return value is std::pair<iterator,bool>, where boolean value indicates whether actual insertion took place or the value already existed. See documentation for return value:
1-2) Returns a pair consisting of an iterator to the inserted element
(or to the element that prevented the insertion) and a bool denoting
whether the insertion took place.

Related

Unexpected behavior using `std::count` on `std::vector` of pairs

My goal is to completely remove all elements in a std::vector<std::pair<int, int>> that occur more than once.
The idea was to utilize std::remove with std::count as part of the predicate. My approach looks something like this:
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
using std::endl;
using i_pair = std::pair<int, int>;
int main()
{
std::vector<i_pair> vec;
vec.push_back(i_pair(0,0)); // Expected to stay
vec.push_back(i_pair(0,1)); // Expected to go
vec.push_back(i_pair(1,1)); // Expected to stay
vec.push_back(i_pair(0,1)); // Expected to go
auto predicate = [&](i_pair& p)
{
return std::count(vec.begin(), vec.end(), p) > 1;
};
auto it = std::remove_if(vec.begin(), vec.end(), predicate);
cout << "Reordered vector:" << endl;
for(auto& e : vec)
{
cout << e.first << " " << e.second << endl;;
}
cout << endl;
cout << "Number of elements that would be erased: " << (vec.end() - it) << endl;
return 0;
}
The array gets reordered with both of the (0,1) elements pushed to the end, however the iterator returned by std::remove points at the last element. This means that a subsequent erase operation would only get rid of one (0,1) element.
Why is this behavior occurring and how can I delete all elements that occur more than once?
Your biggest problem is std::remove_if gives very little guarantees about the contents of the vector while it is running.
It guarantees at the end, begin() to returned iterator contains elements not removed, and from there until end() there are some other elements.
Meanwhile, you are iterating over the container in the middle of this operation.
It is more likely that std::partition would work, as it guarantees (when done) that the elements you are "removing" are actually stored at the end.
An even safer one would be to make a std::unordered_map<std::pair<int,int>, std::size_t> and count in one pass, then in a second pass remove everything whose count is at least 2. This is also O(n) instead of your algorithms O(n^2) so should be faster.
std::unordered_map<i_pair,std::size_t, pair_hasher> counts;
counts.reserve(vec.size()); // no more than this
for (auto&& elem:vec) {
++counts[elem];
}
vec.erase(std::remove_if(begin(vec), end(vec), [&](auto&&elem){return counts[elem]>1;}), end(vec));
you have to write your own pair_hasher. If you are willing to accept nlgn performance, you could do
std::map<i_pair,std::size_t> counts;
for (auto&& elem:vec) {
++counts[elem];
}
vec.erase(std::remove_if(begin(vec), end(vec), [&](auto&&elem){return counts[elem]>1;}), end(vec));

Iterating through two maps in c++

I would like to loop through two maps at the same time, how could I achieve this?
I have two vectors want to print both, can I do two time (auto it : mymap) within one for? Something like:
for (auto it: mymap && auto on: secondMap)
is this even allowed?
I am trying to print values like (value1, value2) where each of the values is in a different map. The maps do not necessarily contain the exact same items but the key is an Instruction and the value is an integer, so if I have a element in the map for value2, then not necessarily there is a value1 corresponding to the same key, but in that case it should be 0 which is the default integer value.
Any ideas?
Perhaps it is possible to combine two iterators, one for each map?
Kind regards,
Guus Leijsten
You can use the regular for-loop for this :
#include <iostream>
#include <map>
int main(int argc, char* argv[]) {
std::map<int, std::string> m1, m2;
m1.insert({15, "lala"});
m1.insert({10, "hey!"});
m1.insert({99, "this"});
m2.insert({50, "foo"});
m2.insert({51, "bar"});
for(auto it_m1 = m1.cbegin(), end_m1 = m1.cend(),
it_m2 = m2.cbegin(), end_m2 = m2.cend();
it_m1 != end_m1 || it_m2 != end_m2;)
{
if(it_m1 != end_m1) {
std::cout << "m1: " << it_m1->first << " " << it_m1->second << " | ";
++it_m1;
}
if(it_m2 != end_m2) {
std::cout << "m2: " << it_m2->first << " " << it_m2->second << std::endl;
++it_m2;
}
}
return EXIT_SUCCESS;
}
Note that because you want to iterate over maps of different size, you have to use the || operator in loop condition. The direct consequence is that you cannot increment in the last part of the for-loop, as one of the iterator may be invalid at that time (and lead to a segmentation fault).
You have to check iterator validity inside the loop and increment it when it's valid, as shown in the sample above.

iterating a vector how to check at which position I am?

Example:
for (vector<string>::reverse_iterator it = myV.rbegin(); it != myV.rend(); ++it)
{
cout << "current value is: " << *it << ", and current position is: " << /* */ << endl;
}
I know I could check how many items there are in the vector, make a counter, and so on. But I wonder if there is a more direct way of checking current index without asserting that I got the length of the vector right.
vector Iterators support difference you can subtract you current iterator it from rbegin.
EDIT
As noted in a comment not all iterators support operator- so std::distance would have to be used. However I would not recommend this as std::distance will cause a liner time performance cost for iterators that are not random access while if you use it - begin() the compiler will tell you that won't work and then you can use distance if you must.
Subtract std::vector<T>::begin() (or rbegin() in your case) from the current iterator. Here's a small example:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> x;
x.push_back(1);
x.push_back(1);
x.push_back(3);
std::cout << "Elements: " << x.end() - x.begin();
std::cout << "R-Elements: " << x.rend() - x.rbegin();
return 0;
}
As pointed out in a really great comment above, std::distance may be an even better choice. std::distance supports random access iterators in constant time, but also supports other categories of iterators in linear time.
Iterators are used to allow generic algorithms to be written that invariant to a choice of a container. I've read in the STL Book that this is great, but may lead to performance drop because sometimes the member functions of a container are optimized for the container and will run faster than generic code that relies on iterators. In this case, if you are dealing with a large vector, you will be calling the std::distance, which although constant is not necessary. If you know that you will be using oly vector for this algorithm, you may recognize that it supports the direct access operator "[]" and write something like this:
#include <vector>
#include <iostream>
using namespace std;
int main ()
{
vector<int> myV;
for (int I = 0; I < 100; ++I)
{
myV.push_back(I);
}
for (int I = 0; I < myV.size(); ++I)
{
cout << "current value is: " << myV[I]
<< ", and current position is: " << I << endl;
}
return 0;
}
In case you are interested in speed, you can always try the different answers proposed here and measure the execution time. It will depend on the vector size probably.
Keep a counter:
for (vector<string>::reverse_iterator it = myV.rbegin(),
int pos = myV.size;
it != myV.rend(),
--pos;
++it)
{
cout << "current value is: " << *it << ", and current position is: " << pos << endl;
}

STL MAP should use find() or [n] identifier to find element in map?

I am confused which is more efficient?
As we can access map directly, why do we need to use find?
I just need to know which way is more efficient.
#include <iostream>
#include <map>
using namespace std;
int main ()
{
map<char,int> mymap;
map<char,int>::iterator it;
mymap['a']=50;
mymap['b']=100;
mymap['c']=150;
mymap['d']=200;
//one way
it=mymap.find('b');
cout << (*it).second <<endl;
//another way
cout << mymap['b'] <<endl;
return 0;
}
thanks in advance! :)
Using find means that you don't inadvertently create a new element in the map if the key doesn't exist, and -- more importantly -- this means that you can use find to look up an element if all you have is a constant reference to the map.
That of course means that you should check the return value of find. Typically it goes like this:
void somewhere(const std::map<K, T> & mymap, K const & key)
{
auto it = mymap.find(key);
if (it == mymap.end()) { /* not found! */ }
else { do_something_with(it->second); }
}
As we can access map directly, why do we need to use find?
Because map<>::operator[] is sometimes nasty. If an element doesn't exist then:
it inserts it
value initialize it
returns reference of value
Thus it always returns a valid reference of value, even if a key din't exist previously. This behavior is not intended many times.
On the other hand map<>::find() is safer; because it returns end(), if a value doesn't exit. Another advantage of find() is that it returns an iterator which contains references to key (first) and value(second) both.
The [] operator in map is not constant it is logarithmic. Most of the books stress on this fact and point out it is a bit misleading. So both find and [] operator are with the same complexity.
Please note that the [] operator will create the entry even if it does not exist while find will return end() in that case.
This code and doc is picked from cplusplus.com
// accessing mapped values
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main ()
{
map<char,string> mymap;
mymap['a']="an element";
mymap['b']="another element";
mymap['c']=mymap['b'];
cout << "mymap['a'] is " << mymap['a'] << endl;
cout << "mymap['b'] is " << mymap['b'] << endl;
cout << "mymap['c'] is " << mymap['c'] << endl;
cout << "mymap['d'] is " << mymap['d'] << endl;
cout << "mymap now contains " << (int) mymap.size() << " elements." << endl;
return 0;
}
OP:
mymap['a'] is an element
mymap['b'] is another element
mymap['c'] is another element
mymap['d'] is
mymap now contains 4 elements.
Notice how the last access (to element 'd') inserts a new element in the map with that key and initialized to its default value (an empty string) even though it is accessed only to retrieve its value. Member function map::find does not produce this effect.

changing value in a stl map in place

I understand that when we insert values into the STL map, a copy is made and stored.
I have code that essentially does a find on the map and obtains an iterator.
I then intend to use the iterator to change the value in the map.
The results are not what I would expect ie: the value is not changed when accessed from another part of the program. I suspect its because the change I am applying is to a copy of
value.
the relevant code is as follows.
ObjectMappingType::iterator it = objectMapping_.find(symbol);
if (it == objectMapping_.end()) {
throw std::invalid_argument("Unknown symbol: " + symbol);
}
get<3>(it->second) = value;
NOTE: I am actually trying to change a value inside a boost::tuple that is stored as the 'value' part of the map.
Hmm... both methods seem to work fine for me. Here's the entire example that I used:
#include <iostream>
#include <map>
#include <string>
#include <boost/tuple/tuple.hpp>
typedef boost::tuple<int, std::string> value_type;
typedef std::map<int, value_type> map_type;
std::ostream&
operator<<(std::ostream& os, value_type const& v) {
os << " number " << boost::get<0>(v)
<< " string " << boost::get<1>(v);
return os;
}
int
main() {
map_type m;
m[0] = value_type(0, "zero");
m[1] = value_type(0, "one");
m[2] = value_type(0, "two");
std::cout
<< "m[0] " << m[0] << "\n"
<< "m[1] " << m[1] << "\n"
<< "m[2] " << m[2] << "\n"
<< std::endl;
boost::get<0>(m[1]) = 1;
map_type::iterator iter = m.find(2);
boost::get<0>(iter->second) = 2;
std::cout
<< "m[0] " << m[0] << "\n"
<< "m[1] " << m[1] << "\n"
<< "m[2] " << m[2] << "\n"
<< std::endl;
return 0;
}
The output is exactly what I would have expected.
lorien$ g++ -I/opt/include -gdwarf-2 foo.cpp
lorien$ ./a.out
m[0] number 0 string zero
m[1] number 0 string one
m[2] number 0 string two
m[0] number 0 string zero
m[1] number 1 string one
m[2] number 2 string two
lorien$
The operator[] on a map will give a reference to the actual contained element, but it has the nasty side-effect of creating a map entry if none existed before. Since you're already checking the result of find() to see if the key exists, you can use it safely.
get<3>(objectMapping_[symbol]) = value;
Without seeing more of your code I can't be sure of this, but it sounds like you could have a threading issue. Does your program use multiple threads by any chance? Maybe not even explicitly, but perhaps you call a library that does some work in a separate thread? Here is what I would do to start debugging.
Have a check that will re-find the value in the map after you set it, and check that it is the correct new value and throw an exception if it is not.
Reproduce the error by accessing the value from the "other part of the program" and see whether it throws the exception
Step through with a debugger to make sure that the modification is indeed happening BEFORE the access in the other part of the program instead of after.
If there are too many accesses to make it practical to do this by hand, dump a trace to a file. That is, add code to append to a log file every time the map is accessed. Each line should have the time of access to as fine a resolution as your system clock allows, the address of the map (so you know you are modifying the same map), the symbol key, the value, and the new value (if this was a modifying access). This way you can pinpoint exactly what times the map modifications are not showing up in the other part of the program, and whether they are before or after the access.