C++ map<K,T> Initialization - c++

I'm reading "Ivor Horton's Beginning Programming Visual C++ 2010", and I'm at Chapter 10-The Standard Template Library. My problem is with the map container map<Person, string> mapname. The book showed me a lot of ways of adding elements to it, such as with the pair<K, T> and using the make_pair() function later, and mapname.insert(pair). But suddenly he introduced an element adding technique used in the following code:
int main()
{
std::map<string, int> words
cout << "Enter some text and press Enter followed by Ctrl+Z then Enter to end:"
<< endl << endl;
std::istream_iterator<string> begin(cin);
std::istream_iterator<string> end;
while(being != end) // iterate over words in the stream
//PROBLEM WITH THIS LINE:
words[*begin++]++; // Increment and store a word count
//there are still more but irrelevant to this question)
}
The indicated line is my problem. I understand that words is the map, but I've never seen such initialization. And what's going on in that thing with its increment. I believe Ivor Horton failed to elaborate this further, or at least he should've given introductions big enough not to suprise noobs like me.

You have such a map:
sts::map<std::string, int> m;
The access operator [key] gives you a reference to the element stored with that key, or inserts one if it doesn't exist. So for an empty map, this
m["hello"];
inserts an entry in the map, with key "Hello" and value 0. It also returns a reference to the value. So you can increment it directly:
m["Bye"]++;
would insert a value 0 under key "Bye" and increment it by one, or increment an existing value by 1.
As for the stuff happening inside the [] operator,
*begin++
is a means to incrementing the istream_iterator and dereferencing the value before the increment:
begin++;
increments begin and returns the value before the increment
*someIterator
dereferences the iterator.

He is doing two things at once, and generally being more clever than he needs to be.
He is getting the value the iterator points to, and then incrementing the iterator. So, interpret *begin++ as *(begin++). Note that it's a postincrement, though, so the increment happens AFTER the dereference.
He is incrementing the value for the given key in your map. When you dereference the iterator, you get a string. This string is used as the key for the words map, whose value is incremented.
Spread over more lines, it looks like this:
std::string x = *begin;
begin++;
words[x] += 1;

Related

Input iterator can be read repeatedly while Output Iterator can only be written once?

I was reading The C++ Programming Language 4th edition by Bjarne Stroustrup. In the iterator chapter (Chapter 31.1.2), it says:
Input iterator: We can iterate forward using ++ and read each element (repeatedly) using *.
Output iterator: We can iterate forward using ++ and write an element once only using *.
I have done many searches on whether input iterator can be read only once or repeatedly, for example:
http://www.cplusplus.com/reference/iterator/InputIterator/
https://www.geeksforgeeks.org/input-iterators-in-cpp/
and most suggests that input iterator can be read once only. But why the author says repeatedly for the input iterator? Is this correct? And if so, why input iterator can be read repeatedly but output iterator can only be written once. I always thought input and output iterator are completely opposite of each other.
Thanks everyone!
The book is correct; and the contradicting sources are not. There appears to be no rule that disallows reading an object more than once by indirecting through an input iterator.
The other sources may be confused by another similar limitation which is that once input iterator has been incremented, all copies of the previous iterator are invalidated, and thus may not be indirected anymore. This limitation is shared by output iterators. By example:
value = *inputIt;
value = *inputIt; // OK
copyIt = inputIt;
++inputIt;
value = *copyIt; // Not OK
The book is also correct that output iterator does have the limitation:
*outputIt = value;
++outputIt;
*outputIt = value; // OK
*outputIt = value; // Not OK
I always thought input and output iterator are completely opposite of each other.
Many output iterators are also input iterators, so "opposite" isn't exactly very descriptive. They are partially overlapping sets of requirements. An iterator can meet both sets of requirements.
If we have *outputIt = 1; then *outputIt = 2; aren't we just assigning to the same *outputit twice?
Yes; And that's something that output iterators are not required to support.
Consider for example an output iterator that sends packets over the internet. You've written a packet, and it has been sent to the internet and received by some other machine. You can't travel back in time and decide that the packet that was sent is something different. You must move on to the next packet and send that instead.
Bjarne's quote is correct. If you have an input iterator you can do *iterator as many times as you want. If you have an output iterator you can only do *iterator once.
What they both have in common though is they can only be used in single pass algorithms. Once you increment either an input or output iterator then an iterator to a previous position is no longer required to be dereferenceable
That means in
while (iterator != end)
{
if (*iterator == some_value)
something = *iterator;
++iterator;
}
iterator has to be an input iterator since we dereference it twice each iteration. On the other hand
while (iterator != end)
{
something = *iterator;
++iterator;
}
works for both an input and output iterators since we do only a single dereference.
You can read through an input iterator as many times as you want to. That comes from the requirement that "(void)*a, *a is equivalent to *a" [input.iterators], see table.
You can only write through an output iterator once. For *r = o, "After this operation r is not required to be dereferenceable". [output.iterators], see table. After you increment r you have a new iterator, and you can again assign through it once.
Once you combine these two into a forward iterator, the restriction on multiple assignments through the same iterator goes away.

Editing the value in an unordered map for a given key

The following is C++ code to get a count of the words in magazine. I'm trying to add the word if its value does not exist and if it does, increment it.
unordered_map<string,int>hash;
vector<string> magazine(m);
for(int i = 0;i <m;i++)
{
cin >> magazine[i];
if(hash[magazine[i]]>0)
hash[magazine[i]]++;
else
hash.emplace(magazine[i],1);
}
But when I try to output, all magazine key gives 0 as value. Any idea why?
Your version doesn't work because this if(hash[magazine[i]]>0) will insert an element into hash if it doesn't exist, this new element will have a mapped value of 0¹. Which means that hash.emplace(magazine[i],1); is pointless here because there will always be an element at magazine[i] now. Because its value will be 0 your hash[magazine[i]]++; will never run either because the if will never be true. Leaving you with a map of i elements, all with value 0.
operator[] returns a reference to the mapped value if there is one, if not, it inserts one and then returns that reference¹.
Which means that you can factor out the if and just change it to:
for(int i = 0;i <m;i++)
{
cin >> magazine[i];
++hash[magazine[i]];
}
Which basically means : "Get a reference to the mapped value for key magazine[i], if none is found, insert one and give me that one. Increment this reference."
¹: If insertion occurs the element is value-initialized. Because your mapped value type is int this will result into the mapped value being 0 after insertion.
if(hash[magazine[i]]>0) creates new item if the key is not exist.
What you really want is:
if(hash.find(magazine[i])!=hash.end())
As #juanchopanza mentioned, you do not need the branching. std::unordered_map::operator [] can handle it like this:
hash[magazine[i]]++;
You are inadvertently creating a new element in the map by doing :
if(hash[magazine[i]]>0)
map<>::operator[] does insertion, value initialization(that value is zero in your case), and then returns the reference of value, all very discreetly.
As correctly suggested in many comments, the best way is:
hash[key]++
Read more.

C++: cannot assign index to iterator

Okay, a small problem with, hopefully, a quick, simple solution.
In my school textbook, in a chapter about the STL, it gives a simple sample program to input for using lists and for using an iterator with a list, like so:
#include <list>
#include <iostream>
#include <string>
using namespace std;
int main()
{
list<int> myIntList;
// Insert to the front of the list.
myIntList.push_front(4);
myIntList.push_front(3);
myIntList.push_front(2);
myIntList.push_front(1);
// Insert to the back of the list.
myIntList.push_back(5);
myIntList.push_back(7);
myIntList.push_back(8);
myIntList.push_back(9);
// Forgot to add 6 to the list, insert before 7. But first
// we must get an iterator that refers to the position
// we want to insert 6 at. So do a quick linear search
// of the list to find that position.
list<int>::iterator i = 0;
for( i = myIntList.begin(); i != myIntList.end(); ++i )
if( *i == 7 ) break;
// Insert 6 were 7 is (the iterator I refers to the position
// that 7 is located. This does not overwrite 7; rather it
// inserts 6 between 5 and 7.
myIntList.insert(i, 6);
// Print the list to the console window.
for( i = myIntList.begin(); i != myIntList.end(); ++i )
cout << *i << " "; cout << endl;
}
Now, at the line that says
list<int>::iterator i = 0;
I get an error in VS 2015 that says:
no suitable constructor exists to convert from"int" to "std::_List_iterator<std::_List_val<std::_List simple_types<int>>>"
What is the problem with the code presented, what is the solution, and why is this a problem to begin with? <-(I'll even settle with a simple grammatical error).
The value 0 may not be a valid value for an iterator. Try either removing the assignment or assigning the iterator to myIntList.begin().
The iterator may not be able to be treated as an index, like with a vector or array. Usually linked lists are not accessed by index; you have to traverse from the beginning.
What is the problem with the code presented
A simple typo in the example.
what is the solution
Replace this line:
list<int>::iterator i = 0;
With this instead:
list<int>::iterator i;
why is this a problem to begin with?
You cannot initialize an iterator with an integer value. Only the container knows what its iterators refer to, so only the container can initialize them. All you can do is request an iterator from a container, assign an iterator to another iterator, and increment/decrement/dereference an iterator. That is all.
From http://www.cplusplus.com/reference/iterator/:
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 (with at least the increment (++) and dereference (*) operators).
This means that an iterator should be able to do the following:
Return the object it's currently "pointing" to (using the * operator)
Change itself to "point" to the next object in its list (using the ++ operator)
A reason for the existence of the iterator as a data type is to create a general way of interacting with different kinds of lists. However, this means that different lists will implement their iterators differently.
In many circumstances, initializing an iterator to a number doesn't make sense because of the implementation under the hood. As a result, we don't define an assignment operator with our iterator type std::vector<int>::iterator on the left and an int on the right. So when you try to assign your iterator to an integral value, list<int>::iterator i = 0; your compiler throws an error.
Let's look at an example where assigning an iterator to 0 doesn't make sense. You could implement an iterator for std::vector<int> as a pointer to an element in your vector. In this case:
* dereferences the pointer stored in vector<int>::iterator and returns its value.
++ modifies the pointer stored in vector<int>::iterator to point at the next element in the list.
However, assigning this pointer to 0 would be the same as assigning it to NULL, and dereferencing it no longer returns a valid element in your vector. (In fact, dereferencing NULL will cause an error!)
To avoid this error, simply make sure that you always assign your iterator to a value of the same type. In the STL, this is usually accomplished by using .begin() to return an iterator that points to the first element in your list.

Variables inside and outside a loop with/without asterix

I am not proficient in C++ but I am converting a short script to PHP
for(auto it = First; it != Last; ++it)
{
Result += *it;
}
From this snippet, I can speculate this simply means
Result = Result + it
where * is a reference to the pointer of the loop.
That said I see this symbol used outside of loops and in some cases I see variables without this symbol both in and outside of loops which puts holes in my theory.
Again I am trying to RTFM but I am unsure what I am searching for.
Both First and Last are iterator objects, representing a generalization of pointers in C++ Standard Library. Additionally, the two iterators reference the same collection, and Last can be reached from First by incrementing the iterator*.
Result is some sort of accumulator. If it is of numeric type, += means Result = Result + *it, where *it is whatever the iterator is pointing to. In other words, Result accumulates the total of elements of the collection between First, inclusive, and Last, exclusive. If First points to the beginning of an array and Last points to one-past-the-end of an array of numeric type, your code would be equivalent to calling PHP array_sum() on the array.
However, Result is not required to be numeric. For example, it could be a std::string, in which case += represents appending the value to the string.
* In terms of pointers and arrays this would be "pointing to the same array," and "Last points to a higher index of the array than First."
I believe your speculation is incorrect.
it, first and last are either iterators or pointers. Iterators are C++ objects that can be used to iterator over containers. For basic usage, they behave much like pointers, and can be dereferenced the same way.
For example:
std::vector<int> myList;
...
// Search for the number 10 in the list.
std::vector<int>::iterator it = std::find(myList.begin(), myList.end(), 10);
// If the number 10 was found in the list, change the value to 11.
if (it != myList.end())
*it = 11; //< Similar to pointer syntax.
In your specific example, the Result variable has a value added to it. To get that value, your code uses the * operator to get the value from the iterator.
The same concept applies to pointers. although iterators and pointers are very different concepts, accessing their values is very similar.

C++ Tokenizing using iterators in an eof() cycle

I'm trying to adapt this answer
How do I tokenize a string in C++?
to my current string problem which involves reading from a file till eof.
from this source file:
Fix grammatical or spelling errors
Clarify meaning without changing it
Correct minor mistakes
I want to create a vector with all the tokenized words. Example: vector<string> allTheText[0] should be "Fix"
I don't understad the purpose of istream_iterator<std::string> end; but I included cause it was on the original poster's answer.
So far, I've got this non-working code:
vector<string> allTheText;
stringstream strstr;
istream_iterator<std::string> end;
istream_iterator<std::string> it(strstr);
while (!streamOfText.eof()){
getline (streamOfText, readTextLine);
cout<<readTextLine<<endl;
stringstream strstr(readTextLine);
// how should I initialize the iterators it and end here?
}
Edit:
I changed the code to
vector<string> allTheText;
stringstream strstr;
istream_iterator<std::string> end;
istream_iterator<std::string> it(strstr);
while (getline(streamOfText, readTextLine)) {
cout << readTextLine << endl;
vector<string> vec((istream_iterator<string>(streamOfText)), istream_iterator<string>()); // generates RuntimeError
}
And got a RuntimeError, why?
Using a while (!….eof()) loop in C++ is broken because the loop will never be exited when the stream goes into an error state!
Rather, you should test the stream's state directly. Adapted to your code, this could look like this:
while (getline(streamOfText, readTextLine)) {
cout << readTextLine << endl;
}
However, you already have a stream. Why put it into a string stream as well? Or do you need to do this line by line for any reason?
You can directly initialize your vector with the input iterators. No need to build a string stream, and no need to use the copy algorithm either because there's an appropriate constructor overload.
vector<string> vec((istream_iterator<string>(cin)), istream_iterator<string>());
Notice the extra parentheses around the first argument which are necessary to disambiguate this from a function declaration.
EDIT A small explanation what this code does:
C++ offers a unified way of specifying ranges. A range is just a collection of typed values, without going into details about how these values are stored. In C++, these ranges are denoted as half-open intervals [a, b[. That means that a range is delimited by two iterators (which are kind of like pointers but more general; pointers are a special kind of iterator). The first iterator, a, points to the first element of the range. The second, b, points behind the last element. Why behind? Because this allows to iterate over the elements very easily:
for (Iterator i = a; i != b; ++i)
cout << *i;
Like pointers, iterators are dereferenced by applying * to them. This returns their value.
Container classes in C++ (e.g. vector, list) have a special constructor which allows easy copying of values from another range into the new container. Consequently, this constructor expects two iterators. For example, the following copies the C-style array into the vector:
int values[3] = { 1, 2, 3 };
vector<int> v(values, values + 3);
Here, values is synonymous with &values[0] which means that it points to the array's first element. values + 3, thanks to pointer arithmetic, is nearly equivalent to &values[3] (but this is invalid C++!) and points to the virtual element behind the array.
Now, my code above does the exact same as in this last example. The only difference is the type of iterator I use. Instead of using a plain pointer, I use a special iterator class that C++ provides. This iterator class wraps an input stream in such a way that ++ advances the input stream and * reads the next element from the stream. The kind of element is specified by the type argument (hence string in this case).
To make this work as a range, we need to specify a beginning and an end. Alas, we don't know the end of the input (this is logical, since the end of the stream may actually move over time as the user enters more input into a console!). Therefore, to create a virtual end iterator, we pass no argument to the constructor of istream_iterator. Conversely, to create a begin iterator, we pass an input stream. This then creates an iterator that points to the current position in the stream (here, cin).
My above code is functionally equivalent to the following:
istream_iterator<string> front(cin);
istream_iterator<string> back;
vector<string> vec;
for (istream_iterator<string> i = front; i != back; ++i)
vec.push_back(*i);
and this, in turn, is equivalent to using the following loop:
string word;
while (cin >> word)
vec.push_back(word);