0

I encountered the following problem:

After I erase a key and a call the key once again from the map, it always returns 0.

So what if the value of a certain key was set to 0?

#include <iostream>
#include <map>

int main(int argc, char const *argv[]) {
  std::map<std::string, int> mymap;

  mymap["a"] = 10;
  mymap["c"] = 10;
  mymap["b"] = 20;
  mymap["zero"] = 0;

  if (mymap["zero"])
    std::cout << "yes" << '\n';
  else
    std::cout << "no" << '\n

    mymap.erase("zero");

  if (mymap["zero"])
    std::cout << "yes" << '\n';
  else
    std::cout << "no" << '\n';


  std::cout << mymap["zero"] << '\n';


  return 0;
}
Miguel Yurivilca
  • 375
  • 5
  • 12

4 Answers4

4

What you need is the count() function. count() will return the number of elements and won't construct an object if it doesn't exist. That would make your if statements look like

if (mymap.count("zero"))
    // key exist here

Since you can use C++17, if you want to do something to the element if found you can leverage it's new if statement syntax that allows you to declare a variable in the if statement and have

if (auto it = mymap.find("zero"); it != mymap.end())
{
    // the element exists and it points to it
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • Beat me by 3 seconds! Clearly I shouldn't have added that `...` at the end :p – scohe001 Oct 26 '18 at 18:52
  • @scohe001 lol. I was really surprised. I hit post and all of the sudden your answer appeared. – NathanOliver Oct 26 '18 at 18:53
  • The `count` solution has a very minor drawback that if you ever change the type of `mymap` to an associative container that allows duplicates it will silently increase the complexity while `find` will not. – François Andrieux Oct 26 '18 at 18:56
  • 1
    @FrançoisAndrieux True. But in the case of the non multi containers I like it better as it is less typing. Good point though. – NathanOliver Oct 26 '18 at 19:00
3

Instead of using if(mymap["key"]) to check if key exists, use .count():

if(mymap.count("zero")) { //key exists!
    ...

Your issue here is that the operator[] will create a new key/value pair if one doesn't exist. From cppreference:

Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.

So if you try to use mymap["zero"] to tell if the key "zero" exists in your map, of course it will--you're creating it!

scohe001
  • 15,110
  • 2
  • 31
  • 51
3

operator [] of map will insert a new entry with default value. You should use find instead:

if (mymap.end() != mymap.find(std::string{"zero"}))
user7860670
  • 35,849
  • 4
  • 58
  • 84
  • So we now have 2 answers for find, and two answers for count. )) – SergeyA Oct 26 '18 at 18:53
  • 1
    I would endorse `find` over `count` because it gives you a useful iterator if you do want to check the value. To retrieve the value after a call to `count` would be to perform two lookups instead of one. – alter_igel Oct 26 '18 at 18:55
  • @alterigel this is why I always use find and never used `count` in my life on a non-multimap. On the other hand, in the given example OP doesn't use the found value, so `count` provides for shorter notation. – SergeyA Oct 26 '18 at 18:57
  • @SergeyA indeed, but it looks like OP is also just starting to learn about `map` and should be aware of `find`, and also get comfortable with the end iterator idiom – alter_igel Oct 26 '18 at 18:58
2

There are several options. The easiest one is to check for presence of an element using std::map::find, rather than operator[], which always creates a default value if it is not there.

The other option is put std::optional as a map data type, and than check if the optional is set.

SergeyA
  • 61,605
  • 5
  • 78
  • 137