I have a big piece code that is analyzing some things related to network.
I need to learn some parts of that code. but I couldn't understand the following part. I don't know such a usage.
unordered_map < string, DomainInfo *>::iterator hostTrafficItr;
As far as I know unordered_map gets a key, map pair and contains it (a container).
Your unordered_map has a key of type string, and value of type DomainInfo*. ::iterator declares hostTrafficItr as an iterator to this map type.
It may be a good idea to read a good C++ reference book. If you need an online reference, you could use this: http://www.cplusplus.com/
This is declaration of (probably standard) unorderd_map (see here http://www.cplusplus.com/reference/unordered_map/unordered_map/) iterator.
unordered_map is key->value structure allowing to access DomainInfo* element using string to identify them.
The iterator is a class allowing you to (as the name says) iterate through collection elements providing you access to collections keys and values.
You can access key connected with current iterator value using:
hostTrafficItr->first //Has type string
and value using
hostTrafficItr->second //Has type DomainInfo*
dereference operator returns pair<string, DomainInfo>.
Iterators are most common initialized by .begin() or .end() of the collection.
HTH
Related
I didn't find any documentation about map in OMNeT++.
I'm trying to sort a map<int,double> by value, not by key, and erase some data.
I declare the map and iterator like this
std::map<int,double> Dlist;
std::map<int,double>::iterator it;
I tried
sort(Dlist.begin(), Dlist.end());
but there is an error.
Also the iterator doesn't return values
iterator.first
iterator.second
First of all this is a pure C++ related problem, since you are using std::map.
std::sort sorts a container in place, therefore there is no iterator which you can access. Additionally, in the given code the declared iterator is not even used.
Secondly, I strongly doubt that you actually want to sort the map's values. Although this is technically possible, it makes no sense: Sorting std::map using value.
Instead you could copy all values from the map into a std::vector and then sort that vector. See Copy map values to vector in STL.
Here is the problem I would like to solve: in C++, iterators for map, multimap, etc are missing two desirable features: (1) they can't be checked at run-time for validity, and (2) there is no operator< defined on them, which means that they can't be used as keys in another associative container. (I don't care whether the operator< has any relationship to key ordering; I just want there to be some < available at least for iterators to the same map.)
Here is a possible solution to this problem: convince map, multimap, etc to store their key/data pairs in a vector, and then have the iterators be a small struct that contain a pointer to the vector itself and a subscript index. Then two iterators, at least for the same container, could be compared (by comparing their subscript indices), and it would be possible to test at run time whether an iterator is valid.
Is this solution achievable in standard C++? In particular, could I define the 'Allocator' for the map class to actually put the items in a vector, and then define the Allocator::pointer type to be the small struct described in the last paragraph? How is the iterator for a map related to the Allocator::pointer type? Does the Allocator::pointer have to be an actual pointer, or can it be anything that supports a dereference operation?
UPDATE 2013-06-11: I'm not understanding the responses. If the (key,data) pairs are stored in a vector, then it is O(1) to obtain the items given the subscript, only slightly worse than if you had a direct pointer, so there is no change in the asymptotics. Why does a responder say map iterators are "not kept around"? The standard says that iterators remain valid as long as the item to which they refer is not deleted. As for the 'real problem': say I use a multimap for a symbol table (variable name->storage location; it is a multimap rather than map because the variables names in an inner scope may shadow variables with the same name), and say now I need a second data structure keyed by variables. The apparently easiest solution is to use as key for the second map an iterator to the specific instance of the variable's name in the first map, which would work if only iterators had an operator<.
I think not.
If you were somehow able to "convince" map to store its pairs in a vector, you would fundamentally change certain (at least two) guarantees on the map:
insert, erase and find would no longer be logarithmic in complexity.
insert would no longer be able to guarantee the validity of unaffected iterators, as the underlying vector would sometimes need to be reallocated.
Taking a step back though, two things suggest to me that you are trying to "solve" the wrong problem.
First, it is unusual to need to have a vector of iterators.
Second, it is unusual to need to check an iterator for validity, as iterators are not generally kept around.
I wonder what the real problem is that you are trying to solve?
I am using std::multimap<> and I pass pointer to an element (T*) to a component written in C.
When the component wants to delete the object it calls back to C++ supplying the pointer, however, I am not sure whether there is a way to convert T* into std::multimap<>::iterator so that I can call erase().
Any ideas?
If you can determine the key from the item, you can use equal_range to get all the possible matches, then call find on that range.
If there isn't a way to get from an item to it's key (rare but possible), then one could enumerate through the whole multimap (from begin() to end()) and erase the one that matches. Hopefully this would be a rare operation, as it is O(N).
Do not confuse pointers and iterators. Sometimes (e.g. arrays) a pointer can function as iterator. But it doesn't necessarily.
Iterators in C++ will usually overload the * operator aka "dereference operator". This makes them look like C pointers even more, when they technically may or may not be the same.
Passing iterators is in general fragile, and I'd avoid this. In particular, a concurrent modification of the multimap in your case may render the iterator invalid.
Remember that a multimap is a set of key-value pairs. It sounds like your T* is a value and you need an efficient way to get its key so you can remove it. Have you considered Boost.Bimap? That library allows efficient mappings both ways. Then it should be simple to take the T* from the calling code, lookup the key, and erase it.
What exactly are iterators in the C++ STL?
In my case, I'm using a list, and I don't understand why you have to make an iterator std::list <int>::const_iterator iElementLocator; to display contents of the list by the derefrence operator:
cout << *iElementLocator; after assigning it to maybe list.begin().
Please explain what exactly an iterator is and why I have to dereference or use it.
There are three building blocks in the STL:
Containers
Algorithms
Iterators
At the conceptual level containers hold data. That by itself isn't very useful, because you want to do something with the data; you want to operate on it, manipulate it, query it, play with it. Algorithms do exactly that. But algorithms don't hold data, they have no data -- they need a container for this task. Give a container to an algorithm and you have an action going on.
The only problem left to solve is how does an algorithm traverse a container, from a technical point of view. Technically a container can be a linked list, or it can be an array, or a binary tree, or any other data structure that can hold data. But traversing an array is done differently than traversing a binary tree. Even though conceptually all an algorithm wants is to "get" one element at a time from a container, and then work on that element, the operation of getting the next element from a container is technically very container-specific.
It appears as if you'd need to write the same algorithm for each container, so that each version of the algorithm has the correct code for traversing the container. But there's a better solution: ask the container to return an object that can traverse over the container. The object would have an interface algorithms know. When an algorithm asks the object to "get the next element" the object would comply. Because the object came directly from the container it knows how to access the container's data. And because the object has an interface the algorithm knows, we need not duplicate an algorithm for each container.
This is the iterator.
The iterator here glues the algorithm to the container, without coupling the two. An iterator is coupled to a container, and an algorithm is coupled to the iterator's interface. The source of the magic here is really template programming. Consider the standard copy() algorithm:
template<class In, class Out>
Out copy(In first, In last, Out res)
{
while( first != last ) {
*res = *first;
++first;
++res;
}
return res;
}
The copy() algorithm takes as parameters two iterators templated on the type In and one iterator of type Out. It copies the elements starting at position first and ending just before position last, into res. The algorithm knows that to get the next element it needs to say ++first or ++res. It knows that to read an element it needs to say x = *first and to write an element it needs to say *res = x. That's part of the interface algorithms assume and iterators commit to. If by mistake an iterator doesn't comply with the interface then the compiler would emit an error for calling a function over type In or Out, when the type doesn't define the function.
I'm being lazy. So I would not type describing what an iterator is and how they're used, especially when there're already lots of articles online that you can read yourself.
Here are few that I can quote for a start, proividing the links to complete articles:
MSDN says,
Iterators are a generalization of
pointers, abstracting from their
requirements in a way that allows a
C++ program to work with different
data structures in a uniform manner.
Iterators act as intermediaries
between containers and generic
algorithms. Instead of operating on
specific data types, algorithms are
defined to operate on a range
specified by a type of iterator. Any
data structure that satisfies the
requirements of the iterator may then
be operated on by the algorithm. There
are five types or categories of
iterator [...]
By the way, it seems the MSDN has taken the text in bold from C++ Standard itself, specifically from the section ยง24.1/1 which says
Iterators are a generalization of
pointers that allow a C + + program to
work with different data structures
(containers) in a uniform manner. To
be able to construct template
algorithms that work correctly and
efficiently on different types of data
structures, the library formalizes not
just the interfaces but also the
semantics and complexity assumptions
of iterators. All iterators i support
the expression *i, resulting in a
value of some class, enumeration, or
built-in type T, called the value type
of the iterator. All iterators i for
which the expression (*i).m is
well-defined, support the expression
i->m with the same semantics as
(*i).m. For every iterator type X for
which equality is defined, there is a
corresponding signed integral type
called the difference type of the
iterator.
cplusplus says,
In C++, an iterator is any object
that, pointing to some element in a
range of elements (such as an array or
a container), has the ability to
iterate through the elements of that
range using a set of operators (at
least, the increment (++) and
dereference (*) operators).
The most obvious form of iterator is a
pointer [...]
And you can also read these:
What Is an Iterator?
Iterators in the Standard C++ Library
Iterator (at wiki entry)
Have patience and read all these. Hopefully, you will have some idea what an iterator is, in C++. Learning C++ requires patience and time.
An iterator is not the same as the container itself. The iterator refers to a single item in the container, as well as providing ways to reach other items.
Consider designing your own container without iterators. It could have a size function to obtain the number of items it contains, and could overload the [] operator to allow you to get or set an item by its position.
But "random access" of that kind is not easy to implement efficiently on some kinds of container. If you obtain the millionth item: c[1000000] and the container internally uses a linked list, it will have to scan through a million items to find the one you want.
You might instead decide to allow the collection to remember a "current" item. It could have functions like start and more and next to allow you to loop through the contents:
c.start();
while (c.more())
{
item_t item = c.next();
// use the item somehow
}
But this puts the "iteration state" inside the container. This is a serious limitation. What if you wanted to compare each item in the container with every other item? That requires two nested loops, both iterating through all the items. If the container itself stores the position of the iteration, you have no way to nest two such iterations - the inner loop will destroy the working of the outer loop.
So iterators are an independent copy of an iteration state. You can begin an iteration:
container_t::iterator i = c.begin();
That iterator, i, is a separate object that represents a position within the container. You can fetch whatever is stored at that position:
item_t item = *i;
You can move to the next item:
i++;
With some iterators you can skip forward several items:
i += 1000;
Or obtain an item at some position relative to the position identified by the iterator:
item_t item = i[1000];
And with some iterators you can move backwards.
And you can discover if you've reached beyond the contents of the container by comparing the iterator to end:
while (i != c.end())
You can think of end as returning an iterator that represents a position that is one beyond the last position in the container.
An important point to be aware of with iterators (and in C++ generally) is that they can become invalid. This usually happens for example if you empty a container: any iterators pointing to positions in that container have now become invalid. In that state, most operations on them are undefined - anything could happen!
An iterator is to an STL container what a pointer is to an array. You can think of them as pointer objects to STL containers. As pointers, you will be able to use them with the pointer notation (e.g. *iElementLocator, iElementLocator++). As objects, they will have their own attributes and methods (http://www.cplusplus.com/reference/std/iterator).
There already exists a lot of good explanations of iterators. Just google it.
One example.
If there is something specific you don't understand come back and ask.
I'd suggest reading about operator overloading in C++. This will tell why * and -> can mean essentially anything. Only then you should read about the iterators. Otherwise it might appear very confusing.
I have the following C++ map example code:
map<string,string> &weight2price
....
weight = ...
price = ...
if(weight2price.find(weight) == weight2price.end())
weight2price[weight] = price;
could anyone tell me what it means by
if(weight2price.find(weight) == weight2price.end())
The STL Map is a standard C++ container. It uses unique keys that can be compared to refer to value data being stored inside the container. It works much like an array but unlike an array, the key can be anything and doesn't need to be an integer.
The syntax for a map is:
std::map < Key, Data, Compare, Alloc>
Key - the type of object that will be used as key
Data - the type of object that will be used as data
Compare - a comparison function for the keys
Alloc - The map's allocator, used for all internal memory management
usage:
map[Key] = Data
For further reading about STL maps look here :
http://en.wikipedia.org/wiki/Map_%28C%2B%2B%29
and here: http://www.sgi.com/tech/stl/Map.html
In the code snippet, you are using the function find() from the map. This function returns an iterator pointing to the element from the map that contains the key you were searching for. If that key is not found, the find function will return the iterator pointing to the end of the map. That is what is being checked in the code snippet you attached to your question and if the find function returned the value of the end iterator, this means that the key is not in the map, so it adds the key and data to the map. An optimization for your code was provided by GMan in his comment.
A very basic explanation for an iterator (although not complete) would be that an iterator is a pointer to a pair< Key,Data>.
Hope this helps!
If the key passed to find() does not exist, find() returns end(). So it's saying "If it wasn't found...".
The code could be written better as:
weight2price.insert(std::make_pair(weight, price));
So look-up isn't done twice. (If the key already exists, insert won't do anything.)
It means that weight was not found. Then if it wasn't found, it adds it.
map in C++ is a like hashmap, where a key (in your case weight) is mapped to a value (price).
Here it checks to see if the particular weight is already mapped in this map, if not the find method will return weight2price.end()
In that case the program enters a key-value pair in the map with the line that you greyed out.