Is it a feature of unordered_map::find() to insert the key that we lookup with 0 value automatically?
Let me make this clear
unordered_map<int, int> tempMap;
//some code
if(tempMap.find(1) == tempMap.end()){
//do something but not insert the 1 with a corresponding value into the tempMap
}
so if I lookup 1 again, will it be there in the tempMap having 0 as corresponding value.
Is that a feature of unordered_map?
No, find only searches and returns an iterator.
That said, std::unordered_map (and std::map) both overload operator[] which will insert a default if needed:
// if element with a key value one exists, return that. otherwise, insert
// a default initialized element (zero in this case), and return that
auto& val = tempMap[1];
No -- find does not insert values.
If you want to insert the value if it was not previously present, then you can use operator[] instead of find.
This is done because operator[] returns a reference to an object. Since there's no such thing as a null reference, essentially the only alternative would be to have it throw an exception when searching for an item that wasn't previously present. There have been some containers that adopted that behavior, but it wasn't apparently very useful and never gained much popularity (I used some containers like that and found it a pain).
Related
std::map and std::set seem very similar to me (but in their use and in their description), so I do not understand why std::set does not implement its version of operator[].
I suspect it is linked to the fact that elements in a std::set are const, but even then why not implement an operator[] that either returns a const reference or creates a new element ?
Depending on the answer to this first question, would it be possible/a good idea to create a version a std::set that implements operator[] ?
Well, std::map<Key, Val> maps Key to Val.
That is, m[key] yields a reference to the val. You have the key, and want to find the associated value (or associate a value with that key).
In a std::set<Elem>, the element would be its own key. So, the only thing you could get back would be the thing you already have. What would you use this operation for?
A set is not for mapping one thing to another - that's what a map does. A set is for recording whether or not an element belongs to some collection. So, the only sane thing to use it for is checking, given some element, whether or not that element is a member of the set. We do this with s.find(elem) != s.end() or, from c++20, s.contains(elem).
The fact that the set is described as std::set<Key, ...> may be a source of confusion - I suspect this is just because it's used for searching in the same way as the map key.
You could in principle choose to characterize a set as map<Elem, bool>, but unless you want to really store the bool (which would be wasteful), the element access and iterator semantics would be a bit hairy. That is, it would be mathematically accurate and consistent, but either wasteful or complicated in implementation.
In fact a map is an associated array only instead of integer indices it uses keys as indices.
As ordinary arrays have the subscript operator then and maps have a similar subscript operator.
On the other hand, sets are not associated arrays. In sets keys are their data. So a question arises what should an expression like this set[key] return? There is no greate sense to return itself and moreover when the returned value may not be changed.
It would not be very useful to use set if you want to know the key of an element, since a map would be more useful, which does have the function you require.
I have read different articles on web and questions at stackoverflow, but for me it is not clear is there any exclusive case when it is better to use std::map::at to retrieve map element.
According to definition, std::map::at
Returns a reference to the mapped value of the element identified with
key k.
If k does not match the key of any element in the container, the
function throws an out_of_range exception.
For me only case when it is worth to use std::map::at when you 100% sure that element with particular key exist, otherwise you should consider exception handling.
Is there any case where std::map::at considered as most efficient and elegant way to do? In what cases you will recommend to use std::map::at ?
Am I right that it is better to use map::find() when there is a possibility to not have element with such a key? And map::find() it is faster and more elegant approach?
if ( map.find("key") != map.end() )
{
// found
} else
{
// not found
}
p.s
map::operator[] sometimes can be dangerous, because if an element doesn't exist then it will inserts it.
EDITED: links somehow related link 1 link 2 link 3 link 4 link 5 link 6
Contrary to most existing answers here, note that there are actually 4 methods related to finding an element in a map (ignoring lower_bound, upper_bound and equal_range, which are less precise):
operator[] only exist in non-const version, as noted it will create the element if it does not exist
at(), introduced in C++11, returns a reference to the element if it exists and throws an exception otherwise
find() returns an iterator to the element if it exists or an iterator to map::end() if it does not
count() returns the number of such elements, in a map, this is 0 or 1
Now that the semantics are clear, let us review when to use which:
if you only wish to know whether an element is present in the map (or not), then use count().
if you wish to access the element, and it shall be in the map, then use at().
if you wish to access the element, and do not know whether it is in the map or not, then use find(); do not forget to check that the resulting iterator is not equal to the result of end().
finally, if you wish to access the element if it exists or create it (and access it) if it does not, use operator[]; if you do not wish to call the type default constructor to create it, then use either insert or emplace appropriately
std::map::at() throws an out_of_range exception if the element could not be found. This exception is a kind of logic_error exception which for me is a kind of synonym of assert() from the usage standpoint: it should be used to report errors in the internal logic of the program, like violation of logical preconditions or class invariants.
Also, you can use at() to access const maps.
So, for your questions:
I will recommend using at() instead of [] when accessing const maps and when element absence is a logic error.
Yes, it's better to use map::find() when you're not sure element is here: in this case it's not a logic error and so throwing and catching std::logic_error exception will not be very elegant way of programming, even if we don't think about performance.
As you noted, there are three different ways to access elements in a map: at(), operator[] and find() (there are also upper_bound, lower_bound and equal_range, but those are for more complicated circumstances where you might want to find a next/previous element etc.)
So, when should you use which one?
operator[] is basically "if it does not exist, create one with a default-constructed mapped element". That means it won't throw (except in the corner cases when the memory allocation throws or one of the key or value constructors throw), and you definitely get a reference to the element you looked for - either the existing one or the newly created.
at() throws if there is no element for that key. Since you should not use exceptions for normal program flow, using at() is saying "I am sure there is such an element." But with the added benefit that you get an exception (and not undefined behavior) if you are wrong. Don't use this if you are not positive that the element exists.
find() says "there may or may not be such an element, let's see..." and offers you the possibility to react to both cases differently. It therefore is the more general approach.
All 3 of find, operator[] and at are useful.
find is good if you don't want to accidentally insert elements, but merely act if they exist.
at is good if you expect that something should be on a map and you'd throw an exception if it wasn't anyway. It can also access const maps in a more concise matter than find (where you can't use op[])
op[] is good if you want to insert a default element, such as for the word counting program which puts an int 0 for every word encountered for the first time (with the idiom words[word]++;).
This depends on what the requirements are for this function and how you are structuring the project. If you are supposed to return an object and you can't because it was not found then it leaves you with two options on how to handle that. You could through an exception or you could return some sort of sentinel that means nothing was found. If you want to throw an exception then use at() as the exception will be thrown for you. If you do not want to throw an exception then use find() so you do not have to deal with handling an exception just to return a sentinel object.
I think, it depends on your usecase. The return type of std::map::at() is an lvalue reference to the value of the found element, while std::map::find() returns an iterator. You might prefer
return myMap.at("asdf"s) + 42;
in expressions over the more elaborate
return myMap.find("asdf"s)->second + 42;
Whenever you use the result of std::map::at() in an expression, you expect the element to exist, and regard a missing element as an error. So an exception is a good choice to handle that.
I guess the difference is semantics.
std::map::at() looks like this on my machine:
mapped_type&
at(const key_type& __k)
{
iterator __i = lower_bound(__k);
if (__i == end() || key_comp()(__k, (*__i).first))
__throw_out_of_range(__N("map::at"));
return (*__i).second;
}
As you can see, it uses lower_bound, then checks for end(), compares keys, and throws the exception where needed.
find() looks like this:
iterator
find(const key_type& __x)
{ return _M_t.find(__x); }
where _M_t is a red-black tree that stores the actual data. Obviously, both function have the same (logarithmic) complexity. When you use find() + check for end(), you are doing almost the same thing that at does. I would say the semantic difference is:
use at() when you need an element at a specific location, and you assume that it is there. In this case, the situation of the element missing from the desired place is exceptional, thus at() throws an exception.
use find() when you need to find the element in the map. In this case the situation when the element is not present is normal. Also note that find() returns an iterator which you may use for purposes other than simply obtaining it's value.
map::at() returns a l-value reference, and when you return by reference, you can use all its available benefits such as method chaining.
example:
map<int,typ> table;
table[98]=a;
table[99]=b;
table.at(98)=table.at(99);
operator[] also returns the mapped value by reference, but it may insert a value if searched for key is not found, in which case container size increases by one.
This requires you to be extra cautious since you have to take care of iterator invalidation.
Am I right that it is better to use map::find() when there is a
possibility to not have element with such a key? And map::find() it is
faster and more elegant approach?
Yes, semantically it makes sense to use find() when you are not sure of the existence of element.Makes the code easier to understand even for a newbie.
As for the time efficiency, map is generally implemented as a RB-tree/some balanced binary search tree and hence, complexity is O(logN) for find().
C++ Spec:
T& operator[](const key_type& x);
Effects: If there is no key equivalent to x in the map, inserts value_type(x, T()) into the map.
Requires: key_type shall be CopyInsertable and mapped_type shall be
DefaultInsertable into *this. Returns: A reference to the
mapped_type corresponding to x in *this. 4 Complexity: Logarithmic.
T& at(const key_type& x);
const T& at(const key_type& x) const;
Returns: A reference to the mapped_type corresponding to x in *this.
Throws: An exception object of type out_of_range if no such element present.
Complexity: Logarithmic.
While looking for an efficient approach to insert to a map only if the key does not exist, I came across this approach:
MapType::iterator lb = mymap.lower_bound(k);
if(lb != mymap.end() && !(mymap.key_comp()(k, lb->first))) {
// key exists. Value accessible from lb->second
} else {
// Do insert. Use lb as a hint to insert so it can avoid another lookup
mymap.insert(lb, MapType::value_type(k, v));
}
That works well for std::map. However, boost::ptr_map does not provide a similar form of insert() i.e. one that accepts an iterator position.
So I'm wondering:
What's the benefit of that approach compared to doing a straight-forward insert? i.e.
std::pair<MapType::iterator, bool> ret;
ret = mymap.insert(MapType::value_type(k, v));
if (!ret.second) {
// key exists. insertion not done. do something else
}
If there's indeed a good reason to use the lower_bound approach, is it there an equivalent strategy for boost::ptr_map? Or would it not be applicable?
there are two most efficient ways to do this.
The first efficient way is just to call insert (as is also the case in STL). This returns pair<iterator,bool> so if it already exists it doesn't insert.
The second way, which you use when you have to create an object if the key doesn't exist, is to use operator[] which returns you a reference to what is there. If the item is not there, it inserts for you with a default-created value.
Note the difference here: for a regular STL map to pointers, operator[] will return you a pointer, and will insert a null one. for boost::ptr_map it will not insert a null pointer, it will insert a pointer to a default-constructed object.
If your collection may actually contain default-constructed objects, and you don't yet have the object you want to insert, I cannot find an efficient way to do it in one go. Perhaps don't use this collection in this case, or ensure that your objects are modified slightly so you have some kind of flag to show it is "default constructed" i.e. a sort of null state.
I want to have a function which searches for a key in a collection of maps and returns an iterator to the found key. But what should be returned in case the key cannot be found? I cannot return map::end since the collection of maps can be empty.
Thanks.
map<string, string>::iterator CConfFile::GetKey(const string &SectionName, const string &KeyName)
{
maps<string, map<string, string> >::const_iterator Section = _Sections.find(SectionName);
if (Section != _Sections.end()) {
map<string, string> &Keys = SectionPtr->second;
map<std::string, string>::const_iterator Key = Keys.find(KeyName);
if (Key != Keys.end())
return Key;
}
cerr << "Key " << KeyName << "not found\n";
return WHAT???;
}
If you return an iterator, then that implies that one can actually iterate over all the values. If thats indeed the case, you would have to return a custom iterator type anyway and you should have no problem to denote a special end iterator.
If the iterator isn't intended to be used as an iterator, it might be better to return a pointer to the found object, and a null pointer in case there isn't any.
You could define your own proxy iterator class, which wraps the map iterator and passes on all operations to it. Then your class can have a special "end" value and you can return that value for not found. Caller then needs a way to get an end proxy iterator, for comparison.
If you want to be really flash, your iterator could know how to "step forward" from the end of one contained map to the beginning of the next one, so that it can be used to iterate over all the maps in the collection. Admittedly not in key order.
Another option is to return a pair of (iterator, bool). Your "deep find" already doesn't return the type that find functions usually return when called with a container (i.e. the iterator type of the container), so you can just go for a total change.
Iterators aren't required to be default-constructible, although they often are. So it's actually a bit tricky to have an "meaningless iterator" and be properly portable. You could try default-constructing your map iterator, though, and if it works in your implementation, use that in the case where the bool is false.
I'm not sure what Boost.Optional does with types which aren't default-constructible, but that might be helpful as a return value.
You could build a special NotAKey-class (see the Null-Object-Pattern), and then have a default map that only contains one object of that class. Whenever no key is found or no map exists, you just return that special iterator.
I think you could also try to write a special iterator to return for such cases yourself, but I never tried that, so I'm not sure.
EDIT: I think sbi's answer is much better than mine, only you should not return a pointer, but a reference, and then use a reference to the Null-Object (could be global singleton) instead of a null-pointer.
Even if this doesn't answer your question I wanted to post in case this can help you.
I find your problem very interesting. We could define of a new generic multi key map class that allows to behave like a map > and in addition as a map, T> allowing to iterate over all the elements on the collection. Boost.Multi-Index allows to define several index over a collection, but I don't think different index can iterate over different types. I will check this and come back with more info.
I don't know what are the other uses of your map of maps, but if you don't need to iterate over the map of keyName you can transform it into a map, string>, and so you will be able to return just map, string>::end.
You should use map::end, since it doesn't point to the last value but it's special value meaning "you've reached end of the list" and doesn't contain any value.
Read http://msdn.microsoft.com/en-US/library/c84shb7e%28v=VS.80%29.aspx
Focus on overview and remarks.
I would like to ask if there is any point of checking if element exists in unorderd_set before inserting it? According to documentation:
Each element is inserted only if it is not equivalent to any other element already in the container (elements in an unordered_set have unique values).
So if I'm getting it correctly in my case:
Element *element = new Element;
//...
if ( my_set.find (element) == my_set.end() )
my_set.insert(element);
It is not required - correct? What actually happens if I try to insert element that is already in the set. Does it do exactly the same check that I am doing?
If you try to insert a value that is already present, the set will remain unchanged. The call will return a pair containing an iterator and Boolean. The Boolean will be false if the item was already present.
http://en.cppreference.com/w/cpp/container/unordered_set/insert
Note that in your case where the set contains pointers it will only prevent you from having duplicate pointers, not duplicate contents. For example,
if your Element object represented an element, like Oxygen, it might contain a value for the atomic number and a string for the name. If you only want oxygen to appear once, a set of pointers will not automatically do this.
An insert() on unorderd_set does a find() to see if the object exists and then inserts the object.
So in your code they are two find(), one explicit, and other inside the insert()