What does "result.second == false" mean in this code? - c++

I came across this c++ code for counting frequency in a vector.
std::map<std::string, int> countMap;
// Iterate over the vector and store the frequency of each element in map
for (auto & elem : vecOfStrings)
{
auto result = countMap.insert(std::pair<std::string, int>(elem, 1));
if (result.second == false)
result.first->second++;
}
from https://thispointer.com/c-how-to-find-duplicates-in-a-vector/. I want to ask what does
result.second == false mean?

Since std::map and the other non-multi associative containers only store unique items there is a chance that when you insert something into it it wont actually insert since it may already be present. insert therefore returns a std::pair<iterator, bool> where the bool will be true if the insert succeeded and false otherwise.
I would like to point out you can get rid of the if statement in the loop. Because of how operator[] of a map works the loop can be replaced with
for (const auto & elem : vecOfStrings) // also added const here since we don't need to modify elem
{
++countMap[elem];
}
And now if elem exists then you increment the value and if it doesn't you added elem to the map and increment its value.

std::map::insert returns a std::pair<iterator, bool>.
pair.first is an iterator to the newly inserted element OR the element that was already in the map and prevented the insertion.
pair.second tells whether or not the insertion happened.
result.second == false is detecting the case where nothing was inserted into the map due to a key collision.
Note that with C++17, this can be written to be a bit more clear:
auto [itr, inserted] = countMap.insert({elem, 1});
if (!inserted) {
itr->second++;
}

From cppreference:
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.
result.first gives you the iterator to the element, while result.second tells you whether the element was actually inserted or did already exist.

std::map::insert returns a pair where the second value indicates whether any insertion actually happened. If the value is false, this means no value was inserted into the map because a value with the same key already exists.
However, the code shouldn’t be written like this: comparing against boolean literals is a nonsensical operation. Instead you’d write
if (not result.second)
// or
if (! result.second)

std::map::insert returns a pair of iterator and a bool. The bool indicates whether the insertion actually took place. The code you listed seems to increment the mapped int if key collision happens on insert.

Related

unordered_map insert on past-the-end iterator

Is it defined and valid behavior that insert through pass-the-end iterator returned by find when the key is not found:
auto it = m.find(key);
if (it == m.end()) {
m.insert(it, make_pair(key, value));
}
because this will save an additional lookup compared using:
m[key] = value;
While it's safe to pass an end iterator as a hint to to unordered_map::insert, it doesn't actually accomplish anything.
Of the three major standard library implementations, only libstdc++ does anything with that hint, and even then it will only end up using it if it points to a valid entry.
If you want to avoid doing two lookups (one to determine if the element is present and another to insert it), you should just try to insert it. insert returns both a bool denoting whether a new element was inserted and an iterator to either the newly-inserted element or the existing element that prevented insertion. That means the most efficient way to insert an element if it doesn't exist and get an iterator to the element is to do something like this:
decltype(m)::iterator it;
bool inserted;
std::tie(it, inserted) = m.insert(std::make_pair(key, value));
if (inserted) {
// ...
}
If your mapped_type is expensive to construct, you can avoid building it with try_emplace (only available with C++17 or later):
auto [it, inserted] = m.try_emplace(key, args, to, value, constructor);
if (inserted) {
// ...
}
Pre C++17, you can just let operator[] default-construct the element and compare the container size to determine if a new element was added:
size_t size_before = m.size();
ValueType& element = m[key];
size_t size_after = m.size();
if (size_before != size_after) {
element = ValueType{args, to, value, constructor};
// ...
}
Obviously this has the drawback of default-constructing the element and only working with assignable types.

Inserting into a std::map and manipulating the obtained iterator to the inserted element

I know that, if I insert a value into a std::map I can obtain an iterator referring to the inserted element (or the element which was previously there) by checking inserts return value like so:
std::map<int, char> m;
auto ret = m.insert(std::make_pair(1, 'A'));
if (ret.second)
std::cout << "it worked" << std::endl;
// ... now iterations over the map starting at ret.first
However, I was wondering whether it is legal to manipulate the obtained iterator afterwards, e.g. assign the desired value in the case of a failure.
std::map<int, char> m;
auto ret = m.insert(std::make_pair(1, 'A'));
if (!ret.second)
ret.first->second = 'A'; // assign the value in case it went wrong
I noticed that this seems to work, but I am not sure whether this is the desired behaviour since everything I found in case of an failed insertion was to use the operator[] instead. However this would not be a solution for me, because I need the iterator returned by insert afterwards and I can't use insert and the operator[] because of performance reasons.
Long story short: Is it valid to manipulate the data referenced by an iterator returned from std::maps insert()?
Long story short: Is is valid to manipulate the data referenced by an iterator returned from std::maps insert()?
Yes, this is just fine. You cannot modify the key as that is const but you can modify the value the key is mapped to as much as you want.

std::map insert() hint location: difference between c++98 and c++11

On cplusplus' entry on map::insert() I read about the location one could add as a hint for the function that the "function optimizes its insertion time if position points to the element that will precede the inserted element" for c++98, while for c++11 the optimization occurs "if position points to the element that will follow the inserted element (or to the end, if it would be the last)".
Does this mean that the performance of code snippets of the following form (which are abundant in the legacy code I'm working on and modeled after Scott Meyer's "Effective STL", item 24) were affected in switching to a C++11-compliant compiler?
auto pLoc = someMap.lower_bound(someKey);
if(pLoc != someMap.end() && !(someMap.key_comp()(someKey, pLoc->first)))
return pLoc->second;
else
auto newValue = expensiveCalculation();
someMap.insert(pLoc, make_pair(someKey, newValue)); // using the lower bound as hint
return newValue;
What would be the best way to improve this pattern for use with C++11?
The C++98 specification is a defect in the standard. See the discussion in LWG issue 233 and N1780.
Recall that lower_bound returns an iterator to the first element with key not less than the specified key, while upper_bound returns an iterator to the first element with key greater than the specified key. If there is no key equivalent to the specified key in the container, then lower_bound and upper_bound return the same thing - an iterator to the element that would be after the key if it were in the map.
So, in other words, your current code already works correctly under the C++11 spec, and in fact would be wrong under C++98's defective specification.
Yes, it will affect the complexity. Giving the correct hint will make insert() have amortized constant complexity, while giving and incorrect hint will force the map to search for the position from the beginning, giving logarithmic complexity. Basically, a good hint makes the insertion happen in constant time, no matter how big your map is; with a bad hint the insertion will be slower on larger maps.
The solution is, apparently, to search for the hint with upper_bound instead of lower_bound.
I am thinking the correct C++11-style hint insertion might be as follows:
iterator it = table.upper_bound(key); //upper_bound returns an iterator pointing to the first element that is greater than key
if (it == table.begin() || (--it)->first < key) {
// key not found path
table.insert(it, make_pair(key, value));
}
else {
// key found path
it->second = value;
}
A snapshot of working lambda function for your reference.
Note: m_map should not be empty. It is trivially known where to add the element if the map is empty.
auto create_or_get_iter = [this] (const K& key) {
auto it_upper = m_map.upper_bound(key);
auto it_effective = it_upper == m_map.begin() ? it_upper : std::prev(it_upper);
auto init_val = it_effective->second;
if (it_effective == m_map.begin() || it_effective->first < key) {
return m_map.insert(it_effective, std::make_pair(key, init_val));
} else {
it_effective->second = init_val;
return it_effective;
}
};

How to get the last element of an std::unordered_map?

How to get the last element of an std::unordered_map?
myMap.rbegin() and --myMap.end() are not possible.
There is no "last element" in a container that is unordered.
You might want an ordered container, e.g. std::map and access the last element with mymap.rbegin()->first (Also see this post)
EDIT:
To check if your iterator is going to hit the end, simply increment it (and possibly save it in a temporary) and check it against mymap.end(), or, even cleaner : if (std::next(it) == last)
In your comments, it appears your goal is to determine if you are on the last element when iterating forward. This is a far easier problem to solve than finding the last element:
template<class Range, class Iterator>
bool is_last_element_of( Range const& r, Iterator&& it ) {
using std::end;
if (it == end(r)) return false;
if (std::next(std::forward<Iterator>(it)) == end(r)) return true;
return false;
}
the above should work on any iterable Range (including arrays, std containers, or custom containers).
We check if we are end (in which case, we aren't the last element, and advancing would be illegal).
If we aren't end, we see if std::next of us is end. If so, we are the last element.
Otherwise, we are not.
This will not work on iterators that do not support multiple passes.
You cant. by definition, the element is not stored based on some sort of order. the key is hashed first and that's why O(1) search is possible. if you wanna check whether a key exists in the unordered_map or not, u can use this code:
std::unordered_map dico;
if(dico.count(key)!=0){
//code here
}
std::unordered_map::iterator last_elem;
for (std::unordered_map::iterator iter = myMap.begin(); iter != myMap.end(); iter++)
last_elem = iter;
// use last_elem, which now points to the last element in the map
This will give you the last element in whatever order the map gives them to you.
Edit: You need to use std::unordered_map<YourKeyType, YourValueType> instead of just std::unordered_map. I just wrote it like this because you did not provide the type in your question.
Alternatively, as suggested by vsoftco (thanks), you could declare both last_elem and iter as decltype(myMap)::iterator.
(If you're compiling with the MSVC++ compiler, then you will need to add typedef decltype(myMap) map_type; and then instead of decltype(myMap)::iterator use map_type::iterator.)
.end() is an iterator to the "element past the last element". That's why you compare it like this when you loop through a map:
for (auto it = myMap.begin(); it != myMap.end(); ++it) // '!=' operator here makes it possible to only work with valid elements
{
}
So you want the "last" element (whatever that may be, because it's not really guaranteed to be the last in an unordered map, since it ultimately depends on how the key was hashed and in which "bucket" it ends up in). Then you need: --myMap.end()
More specifically, .end() is a function, that returns an iterator, same as .begin() returns an iterator. Since there is no .rbegin() in an std::unordered_map, you have to use -- (the decrement operator):
auto it = --myMap.end();
To access the key you use it->first, to access the value you use it->second.
The accepted answer seems wrong. Unordered_map does have the last element even though the key-value pair is not stored in sorted order. Since the iterator of unorered_map is forwar_iterator(LegacyForwardIterator), the cost to find the last element is O(n). Yakk - Adam gave the correct answer. Essentially, you have to iterator the container from begin to end. At each iteration, you have to check whether the next element is end(); if yes then you are at the last element.
You cannot call prev(it) or --it. There will be no syntax error, but you will have a runtime error (more likely segmentation fault) when using the prev(it) or --it. Maybe next version of compiler can tell you that you have an logic error.
It may not be the best solution, performance-wise, but in C++11 and later, I use a combination of std::next() and size() to jump all elements from the beginning of the map, as shown below:
std::unordered_map<int,std::string> mapX;
...
if (mapX.size() > 0) {
std::unordered_map<int,std::string>::iterator itLast =
std::next(mapX.begin(), mapX.size() - 1);
...

C++ list iterator to integer conversion?

Hello guys I have a list iterator type which I want to convert to UINT.
std::set<UINT> volSet;
UINT ssidBase = 1;
UINT ssidEnd = 2;
volSet.insert( ssidBase );
volSet.insert (ssidEnd);
UINT ssidStart = evf::volSet.begin();
I want the first value in the volSet to be set to ssidStart. I'm getting an error when I run this?
cannot convert 'std::_Tree<std::_Tset_traits<unsigned int, std::less< unsigned int>, std::allocator< unsigned int>, false> >::iterator' to 'UINT' in initialization
Any help is appreciated?
As such, iterators in C++ are basically pointers.
So the general idea is that you need to dereference that iterator to access the actual value it points to, like so:
UINT number = *(container.begin());
It is not clear exactly what the intention is with inserting a one and then a two. Granted many more unsigned values can be inserted later. However, by inserting a one, the only other possible value that will be lower is zero. The insert method for the STL set, map, unordered_set, and unordered_map containers (now called Standard Library) returns a pair.
Insert method reference links:
set
http://www.cplusplus.com/reference/set/set/insert/
map
http://www.cplusplus.com/reference/map/map/insert/
unordered_set
http://www.cplusplus.com/reference/unordered_set/unordered_set/insert/
unordered_map
http://www.cplusplus.com/reference/unordered_map/unordered_map/insert/
If the element already exists in a set, the first pair element is the iterator pointing to the existing element with the second element set to false. With a successful insert (e.g. the key is not already present in the set), the first element of the pair points to the element that has been successfully added, with the second pair element set to true.
Using a set to guarantee the first (lowest) element (e.g. where the begin() method will always return an iterator pointing to unless the set is empty), does guarantee that the lowest value in the set is always found in constant time (e.g. O(1); big Oh of one).
A coding example with some values in C++11.
std::set<UINT> volSet;
pair <std::set<UINT>::itertor, bool> p;
//
// Using the same notation on unsigned int for consistency,
// insert 500 unsigned values into the volSet container.
//
for (UINT i = 500; i >= 0; i--)
{
p = volSet.insert(i);
if (p.second == false)
{
cerr << "volSet insertion warning!! The value for volSet already has: ";
cerr << i << endl;
}
}
//
// Do business logic, deletions/insertions from/to the volSet, and so on...
//
// Now obtain the lowest value inside the volSet and set it to a local variable.
// It is assumed that evf is a user defined namespace.
//
std::set<UINT>::iterator ii = evf::volSet.begin();
UINT ssidStart = *ii;
//
// Alternatively, implement without declaring a local iterator as Victor
// has shown above. Note that the parenthesis here are important. The call
// to begin() has to occur prior to the dereference operator call.
// Note that the sample above intentionally sets the ii iterator
// before dereferencing.
//
UNIT lowValue = *(evf::volSet.begin());
I hope this is helpful to understand the difference between iterators and container elements.