How do I know if std::map insert succeeded or fail

2020-08-25 09:35发布

问题:

I have a map in a multithreaded app mapping a class called uuid to pointer. What I want to know if an insert operation succeeded for failed.

e.g.

_mymap.insert(hint, MyMap::value_type(entry.uuid, itemptr));

Does it throw an exception or something if it fails?

回答1:

In fact the insert method which takes a hint parameter does not return whether the insert succeeded or not. One way to check if insert actually happened would be to check the size of the map before and after insertion. If it is the same, then insert has failed (i.e. the key was already present). I know it sounds ugly, but that's the most efficient way I could come up with. In fact I believe that there is no compelling reason that the insert with a hint should not return a pair (including the bool) just like the regular non-hint insert does. But once it has been specified in an older standard, it is very hard to change, since it is a breaking change, which the C++ community mostly resents.

Original (wrong) answer

See this link

... returns a pair, with its member pair::first set to an iterator pointing to either the newly inserted element or to the element that already had its same value in the map. The pair::second element in the pair is set to true if a new element was inserted or false if an element with the same value existed.

The link also contains an example

For example:

if(mp.insert(make_pair(key, value)).second == false)
{
   cout << "Insertion failed. Key was present"
}


回答2:

typedef std::map<std::string, int> map;
map m;
std::pair<map::iterator,bool> result = m.insert(std::make_pair("hi", 42));

result.second contains what you want



回答3:

It depends what you mean by failed or succeeded.

std::map::insert succeeds when it inserts the new element or returns an iterator to an already existing element.

std::map::insert fails if there is not enough memory to insert a new element and throws std::bad_alloc.



回答4:

Yes, it would throw one of the exceptions used in the STL, e.g. when out of memory. That is in case of failure.

Or were you also interested in knowing whether the element was already contained in the instance?



回答5:

The first insert member function returns a pair whose bool component returns true if an insertion was made and false if the map already contained an element whose key had an equivalent value in the ordering, and whose iterator component returns the address where a new element was inserted or where the element was already located.

To access the iterator component of a pair pr returned by this member function, use pr.first, and to dereference it, use *(pr.first). To access the bool component of a pair pr returned by this member function, use pr.second.

The second insert member function, the hint version, returns an iterator that points to the position where the new element was inserted into the map.

Source: http://msdn.microsoft.com/en-us/library/81ac0zkz(v=vs.80).aspx



回答6:

It is also possible to know if a pair was inserted or found in a map after insertion with hint (much faster).

Insert with hint method another pair of the same first, and of a second that you are sure is not in the map ( like (size_t) -1 for a map of sizes for instance ?). If the iterator returned has this impossible value, it has been newly inserted, if not it was found in the map. The iterator returned may then be changed. Example : to insert pairs p (2,4) and p (6, 5) in the map m ((0, 1), (2, 3), (4, 5)).

int main (int argc, char* argv []) {
  std::pair<size_t, size_t> tmp [3] = {
    std::pair<size_t, size_t> (0, 1),
    std::pair<size_t, size_t> (2, 3),
    std::pair<size_t, size_t> (4, 5)
  };
  std::map<size_t, size_t> m ((std::pair<size_t, size_t>*) tmp, (std::pair<size_t, size_t>*) &tmp [3]);

  std::cout << "initial map == ";
  std::for_each (m.begin (), m.end (), [] (const std::pair<size_t, size_t>& p) {
    std::cout << p.first << "->" << p.second << "   ";
  });
  std::cout << std::endl;
  std::cout << std::endl;

  {
    //insertion of a pair of first already in map
    std::cout << "insertion of pair 1 == std::pair<size_t, size_t> (2, 4) from second iterator" << std::endl;
    std::map<size_t, size_t>::iterator ihint (m.begin ()), k (ihint); ++ihint;
    std::pair<size_t, size_t> pfoo (2, (size_t) -1);
    k = m.insert (ihint, pfoo);
    if (k->second == (size_t) -1) {
      std::cout << "\tthe pair was inserted" << std::endl;
      k->second = 4;
    }
    else {
      std::cout << "\ta pair with such a first was in the map" << std::endl;
    }
  }
  std::cout << "m after insertion of pair 1 == ";
  std::for_each (m.begin (), m.end (), [] (const std::pair<size_t, size_t>& p) {
    std::cout << p.first << "->" << p.second << "   ";
  });
  std::cout << std::endl;
  std::cout << std::endl;

  {
    //insertion of a pair of first not in map
    std::cout << "insertion of pair 2 == std::pair<size_t, size_t> (6, 5) from third iterator" << std::endl;
    std::map<size_t, size_t>::iterator ihint (m.begin ()), k (ihint); ++ihint; ++ihint;
    std::pair<size_t, size_t> pfoo (6, (size_t) -1);
    k = m.insert (ihint, pfoo);
    if (k->second == (size_t) -1) {
      std::cout << "\tthe pair was inserted" << std::endl;
      k->second = 5;
    }
    else {
      std::cout << "\ta pair with such a first in the map" << std::endl;
    }
  }
  std::cout << "m after insertion of pair 2 == ";
  std::for_each (m.begin (), m.end (), [] (const std::pair<size_t, size_t>& p) {
    std::cout << p.first << "->" << p.second << "   ";
  });
  std::cout << std::endl;
}

outputs : initial map == 0->1 2->3 4->5

insertion of pair 1 == std::pair (2, 4) from second iterator

a pair with such a first was in the map

m after insertion of pair 1 == 0->1 2->3 4->5

insertion of pair 2 == std::pair (6, 5) from third iterator

the pair was inserted

m after insertion of pair 2 == 0->1 2->3 4->5 6->5



标签: c++ linux gcc stl