std::map and its siblings(std::multimap, std::unordered_map/multimap) used to be my favourite containers when I was doing competitive programming. In fact, I still like them(though using less frequently nowadays). And with Modern C++, we now have more reasons to use std::map. That’s why I have decided to address this topic by writing an article summarizing these new features. So, without much gibberish, let’s dive-in directly.
/!: This article has been originally published on my blog. If you are interested in receiving my latest articles, please sign up to my newsletter.
std::map::contains
member function is a good step towards code expressiveness. And I am also tire of writing :if (auto search = freq_of.find(2); search != freq_of.end()) {
cout << "Found" << endl;
}
// Where assume, freq_of = map<uint32_t, uint32_t>{{3, 1}, {1, 1}, {2, 1}};
if (freq_of.contains(2)) {
cout << "Found" << endl;
}
The code we write is written first for human consumption & only secondarily for the computer to understand.
- John Sonmez
std::map
is by using operator[ ]
, std::map::insert
or std::map::emplace
. But, in all of these cases, we have to bear the cost of default/specialized constructor or assignment call. And the worst part is if an item already exists, we have to drop the freshly created item.int main() {
vector v{3, 4, 5, 8, 7, 3, 5, 2, 4};
map<uint32_t, uint32_t> freq_of;
for (const auto &n : v) {
if (const auto &[it, inserted] = freq_of.emplace(n, 1); !inserted) {
it->second++; // Exists already
}
}
assert(freq_of[3] == 2);
return EXIT_SUCCESS;
}
if (const auto &[it, inserted] = freq_of.try_emplace(n, 1); !inserted) {
it->second++;
}
std::map::try_emplace
.std::map::operator[ ]
isn’t feasible. Rather, **_std::map::insert_or_assign_**
_ is more appropriate and returns more information than _[**_std::map::operator[ ]_**](https://dev.tostd::map::operator%5B%20%5D/)
. It also does not require default-constructibility of the mapped type. Consider the following example for the same.int main() {
vector v{8, 3, 9, 5, 8};
map<uint32_t, uint32_t> freq_of;
for (auto &&n : v) {
const auto &[it, is_inserted] = freq_of.insert_or_assign(n, 1);
if (!is_inserted) { // remove all lesser element then current one if repeated
freq_of.erase(begin(freq_of), it);
}
}
assert((freq_of == decltype(freq_of){
{8, 1},
{9, 1},
}));
return EXIT_SUCCESS;
}
#programming #coding #cpp11 #cpp #computer-science