Variables inside and outside a loop with/without asterix - c++

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.

Related

Can we take the value of iterator which was returned from lower_bound as vector index?

I'm new to vector in C++ and trying to get how it works.
First, I have a vector array:
vector<int>container;
Then I want to get the position of a given number in a vector array.
vector<int>::iterator position;
position = lower_bound(container.begin(), container.end(), temp);
After that, I want to get the value at that position that was returned from lower_bound by
container[position]
But I get the error that
No viable overloaded operator[] for type 'vector'
When I change it into *(position+1), it works fine.
So what is the different between those two?
Welcome to stackoverflow :)
First of all, we should understand what an iterator is. According to the hackingcpp
objects that point to a location
may point to a readable memory address / object
..
There are a lot of containers in C++ STL, such as vector, list, map and others.
A iterator is an abstraction of pointer, which allows you to access elements stored in container, use algorithm(such as sort, find, lower_bound) provided by STL no matter what kind of container we have.
Therefore, the return type of std::lower_bound is an iterator as you know vector<int>::iterator,
You couldn't access an element by calling container[position], there is no such function vector[iterator] provided by vector.
When I change it into *(position+1)
*itreator means return the value of where an iterator points out.
By the way, it's dangerous to do something like this *(position+1).
Since perhaps the given value tmp is in vector, perhaps it's not, so you should check whether the given value tmp is in vector by calling iterator != vector.end().
std::lower_bound returns a ForwardIterator (See: C++ named requirements: LegacyForwardIterator).
You can dereference it just like you would a pointer, eg:
std::vector<int> container;
// ...
auto it = std::lower_bound(container.begin(), container.end(), foo);
if (container.end() == it) {
throw or_something("handle error?");
}
const int x = *it;
const int y = container[std::distance(container.begin(), it)];
In that example x == y is true. (See: Compiler Explorer)

why iterator doesnt get to end of vector?

I made a vector v which is [-5,-3]. I assigned an iterator iti to its beginning and then assigned another iterator itj as iti+1. Since my vector only has 2 elements, I would think that itj is recognized as the end of the vector or v.end(). But it is not.
Any ideas why that might be happening?
vector<int>v;
v.push_back(-5);
v.push_back(-3);
vector<int>::iterator iti, itj;
iti = v.begin();
itj = iti + 1;
if(itj==v.end())
cout << "1";
else
cout << "2";
Why does this print out '2' and not '1'?
end is an iterator to the (non-existing) element after the last element. iti + 2 would equal end because the vector has 2 elements. Generally, for a vector of size N: begin + N equals end.
The definition of vector:: end() is made in such a way that it returns the iterator which points to the (imaginary) element next to the last element.
Now, this might appear stupid initially, but is actually very useful, because, generally you use an iterator to iterate through a vector. And that is usually done using a for loop. So people do
for (vector<int>:: iterator i = v.begin();i!=v.end();i++)
which iterates over the whole vector.
Now I am not saying that we cannot achieve this if end returns an iterator to the last element. It is of course possible to do it, if we change the structure of our loop a little.
So, let us assume for a moment that end does return an iterator pointing to the last element. Now try to write a piece of code to iterate over the whole vector, say to print it. You will understand why the designers chose this kind of a convention. Remember that you cannot compare two iterators with <= like you do with normal integer indices.
BTW, it is the same convention for all STL containers.

How to get position of a certain element in strings vector, to use it as an index in ints vector? (= original name of thread)

because of not enough reputation I can't comment a post on the the thread:
How to get position of a certain element in strings vector, to use it as an index in ints vector?
I want to know something regarding this answer:
Original answer on thread:
To get a position of an element in a vector knowing an iterator pointing to the element, simply subtract v.begin() from the iterator:
ptrdiff_t pos = find(Names.begin(), Names.end(), old_name_) - Names.begin();
Now you need to check pos against Names.size() to see if it is out of bounds or not:
if(pos >= Names.size()) {
//old_name_ not found
}
vector iterators behave in ways similar to array pointers; most of what you know about pointer arithmetic can be applied to vector iterators as well.
Starting with C++11 you can use std::distance in place of subtraction for both iterators and pointers:
ptrdiff_t pos = distance(Names.begin(), find(Names.begin(), Names.end(), old_name_));
Questions:
How does this exactly work for the compiler? What happens in the background?
I know, that im passing two iterators to the find method, which seems logic: I pass the start and the end position. In between, I'm searching for the element. std::find() returns an iterator of the first element satisfying the value passed as third parameter to the std::find() method. So is std::distance doing nothing else than incrementing in a for loop something like a counter until it reaches the "end-point" iterator?
I could also write:
int index = distance(Names.begin(), find(Names.begin(), Names.end(), old_name_));
Why is it better to use ptrdiff_t than an integer? Someone commented in the original post that it lets you store the distance between any pair of iterators into the same container, even in situations when the result is negative. But I do not really get the point of it. Maybe you could explain that a bit further. (:
I'm coming from C#, where you can use something like (demonstrated on a string):
string test = "Hello World";
int index = test.IndexOf("d");
This seems a lot easier compared to the methods used above in C++. Is there something equivalent in C++?
Thank you very much for your help!
Best regards

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.

What is the past-the-end iterator in STL C++?

Any one could explain me what is the meaning of past-the-end. Why we call end() function past-the-end?
The functions begin() and end() define a half open range([begin, end)), which means:
The range includes first element but excludes the last element. Hence, the name past the end.
The advantage of an half open range is:
It avoids special handling for empty ranges. For empty ranges, begin() is equal to
end() .
It makes the end criterion simple for loops that iterate over the elements: The loops simply
continue as long as end() is not reached
Because it doesn't point to the last element of a container, but to somewhere past the last element of a container.
If you dereference end() it results in undefined behaviour.
Like interval in mathematics, stl uses [begin, end).
That's why we could write for (auto it = v.begin(); it != v.end(); ++it)
Literally, because it points one past the end of the array.
It is used because that element is empty, and can be iterated to, but not dereferenced.
int arry[] = {1, 2, 3, 4, /* end */ };
^^^^^^^
std::end(arry) would point here.
Adding another point to the above correct answers.
This was also done to be compatible with arrays.
For example in the code below:
char arr[5];
strcpy(arr, "eakgl");
sort(&arr[0], &arr[5]);
This will work fine.
Instead if you had given :
sort(&arr[0], &arr[4]);
it would miss sorting the last character.
This also helps to represent empty containers naturally.