I would like to know if it is possible to obtain an iterator to an object inside a container (e.g. std::vector<...>) by only having access to the object inside the container, e.g. through a reference (which implies we have access to a pointer to it using the & operator). For example, normally we declare an iterator as
std::vector<int>::iterator = vec.begin();
or
std::vector<int>::iterator = next(vec.begin(), idx);
but in the first example we are most probably about to iterate through the container, in order, while in the second example we know the index of the object we require. I would like to know if we can obtain the iterator to an object without knowing at which index it resides in the container, but if we do have a reference or a pointer to it, as explained above.
It might appear that this question has already been asked here, but it seems more like the OP wanted others to fix his code, rather than answering the general question, so the answers are not so satisfactory in my opinion. Also, the answer here seems to say that we can initialize an iterator with a constructor, as shown below
std::vector<int>::iterator it(...);
but I have not been able to find any evidence of a constructor for the std::iterator class in the official documentation (and neither have I been able to find any documentation on std::vector<...>::iterator) so I am wary to use the constructor shown above, even if it compiles.
NOTE
I use std::vector as an example above, but ideally I would like this to work for any container, e.g. std::list or std::deque
Specifically for std::vector (and other contiguous containers like std::string), given a pointer to an object in the vector p, we can simply do:
auto iter = v.begin() + std::distance(v.data(), p);
This is guaranteed by the contiguity contract. Note that random access is insufficient here, the above will not work for std::deque.
For any other container, there's no easy way of doing this. You'd have to just use find_if:
auto iter = std::find_if(c.begin(), c.end(), [p](auto const& o) { return &o == p; });
For intrusive containers, the iterator will be encoded into the object itself somehow so there will be some direct mechanism for converting p to an iterator. But that will be dependent on the intrusive container itself.
You can use the find function---it returns an iterator---, supported on (almost?) all containers, to find your objects. If there are several objects which are equal under the operator==, iterate until the one with the same address has been found.
Since C++11 you can use the keyword auto to deduce the type, it makes writing the type easier.
If we know the index we can get an iterator to it bybegin() + index.
And if we don't know the index we could use the std::distance() from begin and the other iterator, which will give us an iterator to the same element.
// if we know the index
auto it1 = begin(vec) + 4;
cout << *it1;
// if we don't know the index
auto p = begin(vec) + 3;
auto it2 = begin(vec) + distance(begin(vec), p+1);
cout << *it2;
Related
I would like to know if it is possible to obtain an iterator to an object inside a container (e.g. std::vector<...>) by only having access to the object inside the container, e.g. through a reference (which implies we have access to a pointer to it using the & operator). For example, normally we declare an iterator as
std::vector<int>::iterator = vec.begin();
or
std::vector<int>::iterator = next(vec.begin(), idx);
but in the first example we are most probably about to iterate through the container, in order, while in the second example we know the index of the object we require. I would like to know if we can obtain the iterator to an object without knowing at which index it resides in the container, but if we do have a reference or a pointer to it, as explained above.
It might appear that this question has already been asked here, but it seems more like the OP wanted others to fix his code, rather than answering the general question, so the answers are not so satisfactory in my opinion. Also, the answer here seems to say that we can initialize an iterator with a constructor, as shown below
std::vector<int>::iterator it(...);
but I have not been able to find any evidence of a constructor for the std::iterator class in the official documentation (and neither have I been able to find any documentation on std::vector<...>::iterator) so I am wary to use the constructor shown above, even if it compiles.
NOTE
I use std::vector as an example above, but ideally I would like this to work for any container, e.g. std::list or std::deque
Specifically for std::vector (and other contiguous containers like std::string), given a pointer to an object in the vector p, we can simply do:
auto iter = v.begin() + std::distance(v.data(), p);
This is guaranteed by the contiguity contract. Note that random access is insufficient here, the above will not work for std::deque.
For any other container, there's no easy way of doing this. You'd have to just use find_if:
auto iter = std::find_if(c.begin(), c.end(), [p](auto const& o) { return &o == p; });
For intrusive containers, the iterator will be encoded into the object itself somehow so there will be some direct mechanism for converting p to an iterator. But that will be dependent on the intrusive container itself.
You can use the find function---it returns an iterator---, supported on (almost?) all containers, to find your objects. If there are several objects which are equal under the operator==, iterate until the one with the same address has been found.
Since C++11 you can use the keyword auto to deduce the type, it makes writing the type easier.
If we know the index we can get an iterator to it bybegin() + index.
And if we don't know the index we could use the std::distance() from begin and the other iterator, which will give us an iterator to the same element.
// if we know the index
auto it1 = begin(vec) + 4;
cout << *it1;
// if we don't know the index
auto p = begin(vec) + 3;
auto it2 = begin(vec) + distance(begin(vec), p+1);
cout << *it2;
I have a std::vector and I want the iterator to the last element in the vector; I will be storing this iterator for later use.
NOTE: I want an iterator reference to it, not std::vector::back. Because I want to be able to compute the index of this object from the std::vector::begin later on.
The following is my logic to get the iterator to the last element:
std::vector<int> container;
std::vector<int>::iterator it = container.end()--;
Since std::vector::end has O(1) time complexity, is there a better way to do this?
I think you mean either:
std::vector<int>::iterator it = --container.end();
std::vector<int>::iterator it = container.end() - 1;
std::vector<int>::iterator it = std::prev(container.end());
You're unintentionally just returning end(). But the problem with all of these is what happens when the vector is empty, otherwise they're all do the right thing in constant time. Though if the vector is empty, there's no last element anyway.
Also be careful when storing iterators - they can get invalidated.
Note that if vector<T>::iterator is just T* (which would be valid), the first form above is ill-formed. The second two work regardless, so are preferable.
You have rbegin that does what you need
cplusplus reference
auto last = container.rbegin();
The way you are doing it will give you the wrong iterator because post increment will not change the value until after the assignment.
There is always this:
auto it = std::prev(container.end());
Remember to check first that the container is not empty so your iterator exists in a valid range.
There are so many alternative ways of addressing elements of a vector.
I could use a pointer like so:
vector<int> v = {10, 11, 12};
int *p = &v[0];
cout << *p; //Outputs "10"
I could use a pointer this way too:
vector<int> v = {10, 11, 12};
vector<int>::pointer p = v.data();
cout << *p; //Outputs "10"
I could also use the iterator type:
vector<int> v = {10, 11, 12};
vector<int>::iterator i = v.begin();
cout << *i; //Outputs "10"
Are there any significant differences that I'm missing here?
As far as being able to perform the task at hand, they all work equally well. After all, they all provide an object which meets the requirements of an iterator and you are using them to point at the same element of the vector. However, I would pick the vector<int>::iterator option because the type is more expressive about how we intend to use it.
The raw pointer type, int*, tells you very little about what p is, except that it stores the address of an int. If you think about p in isolation, its type doesn't tell you very much about how you can use it. The vector<int>::pointer option has the same issue - it just expresses the type of the objects it points at as being the element type of a vector. There's no reason it actually needs to point into a vector.
On the other hand vector<int>::iterator tells you everything you need to know. It explicitly states that the object is an iterator and that iterator is used to point at elements in a vector<int>.
This also has the benefit of being more easily maintainable if you ever happen to change the container type. If you changed to a std::list, for example, the pointer type just wouldn't work any more because the elements are not stored as a contiguous array. The iterator type of a container always provides you with a type you can use to iterate over its elements.
When we have Concepts, I'd expect the best practise to be something like:
ForwardIteratorOf<int> it = std::begin(v);
where ForwardIteratorOf<int> (which I am imagining exists) is changed to whatever concept best describes your intentions for it. If the type of the elements doesn't matter, then just ForwardIterator (or BidirectionalIterator, RandomAccessIterator, or whatever).
If you add the check:
if ( !v.empty() )
Then, all the example you've shown are equally valid.
If you are about to iterate over the elements of the vector, I would go with:
vector<int>::iterator i = v.begin();
It's easier to check whether the iterator has reached the end of the vector with an iterator than with the other forms.
if ( i != v.end() )
{
// Do stuff.
}
All these ways have their advantages, but at the core they are very similar. Some of them don't work though (they cause so-called "undefined behaviour") when the vector is empty.
According to cppreference:
A pointer to an element of an array satisfies all requirements of LegacyContiguousIterator
which is the most powerful iterator as it encompasses all other iterators functionality. So they can be one and the same, an iterator is just a means of making our code clear, consice and portable.
For example we could have some container "C"...
//template <typename T, int N> class C { //for static allocation
template <typename T> class C {
//T _data[N]; //for static allocation
T* _data; //need to dynamically allocate _data
public:
typedef T* iterator;
}
where C<int>::iterator would be an int* and there would be no difference.
Maybe we don't want/need the full power of a LegacyContiguousIterator so we could redefine C<int>::iterator
as another class that follows the outline for say LegacyForwardIterator. This new iterator class may redefine operator*. In this case it is implementation dependant and an int* may cause undefined behaviour when trying to access the elements.
This is why iterators should be preferred but in most cases they are going to be the same thing.
In both cases our container " C" will work just like other STL containers so long as we define all the other necessary member functions and typedefs.
I'm a Java developer. I'm currently learning C++. I've been looking at code samples for sorting. In Java, one normally gives a sorting method the container it needs to sort e.g
sort(Object[] someArray)
I've noticed in C++ that you pass two args, the start and end of the container. My question is that how is the actual container accessed then?
Here's sample code taken from Wikipedia illustrating the the sort method
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> vec;
vec.push_back(10); vec.push_back(5); vec.push_back(100);
std::sort(vec.begin(), vec.end());
for (int i = 0; i < vec.size(); ++i)
std::cout << vec[i] << ' ';
}
vec.begin() and vec.end() are returning iterators iterators. The iterators are kind of pointers on the elements, you can read them and modify them using iterators. That is what sort is doing using the iterators.
If it is an iterator, you can directly modify the object the iterator is referring to:
*it = X;
The sort function does not have to know about the containers, which is the power of the iterators. By manipulating the pointers, it can sort the complete container without even knowing exactly what container it is.
You should learn about iterators (http://www.cprogramming.com/tutorial/stl/iterators.html)
vec.begin() and vec.end() do not return the first and last elements of the vector. They actually return what is known as an iterator. An iterator behaves very much like a pointer to the elements. If you have an iterator i that you initialised with vec.begin(), you can get a pointer to the second element in the vector just by doing i++ - the same as you would if you had a point to the first element in an array. Likewise you can do i-- to go backwards. For some iterators (known as random access iterators), you can even do i + 5 to get an iterator to the 5th element after i.
This is how the algorithm accesses the container. It knows that all of the elements that it should be sorting are between begin() and end(). It navigates around the elements by doing simple iterator operations. It can then modify the elements by doing *i, which gives the algorithm a reference to the element that i is pointing at. For example, if i is set to vec.begin(), and you do *i = 5;, you will change the value of the first element of vec.
This approach allows you to pass only part of a vector to be sorted. Let's say you only wanted to sort the first 5 elements of your vector. You could do:
std::sort(vec.begin(), vec.begin() + 5);
This is very powerful. Since iterators behave very much like pointers, you can actually pass plain old pointers too. Let's say you have an array int array[] = {4, 3, 2, 5, 1};, you could easily call std::sort(array, array + 5) (because the name of an array will decay to a pointer to its first element).
The container doesn't have to be accessed. That's the whole point of the design behind the Standard Template Library (which became part of the C++ standard library): The algorithms don't know anything about containers, just iterators.
This means they can work with anything that provides a pair of iterators. Of course all STL containers provide begin() and end() methods, but you can also use a regular old C array, or an MFC or glib container, or anything else, just by writing your own iterators for it. (And for C arrays, it's as simple as a and a+a_len for the begin and end iterators.)
As for how it works under the covers: Iterators follow an implicit protocol: you can do things like ++it to advance an iterator to the next element, or *it to get the value of the current element, or *it = 3 to set the value of the current element. (It's a bit more complicated than this, because there are a few different protocols—iterators can be random-access or forward-only, const or writable, etc. But that's the basic idea.) So, if `sort is coded to restrict itself to the iterator protocol (and, of course, it is), it works with anything that conforms to that protocol.
To learn more, there are many tutorials on the internet (and in the bookstore); there's only so much an SO answer can explain.
begin() and end() return iterators. See e.g. http://www.cprogramming.com/tutorial/stl/iterators.html
Iterators act like references into part of a container. That is, *iter = z; actually changes one of the elements in the container.
std::sort actually uses a swap function on references to the contained objects, so that any iterators you have already initialized remain in the same order but the values those iterators refer to are changed.
Note that std::list also has member functions called sort. It works the other way around: any iterators you have already initialized keep the same values, but the order of those iterators changes.
I am a little bit frustrated of how to use vectors in C++. I use them widely though I am not exactly certain of how I use them. Below are the questions?
If I have a vector lets say: std::vector<CString> v_strMyVector, with (int)v_strMyVector.size > i can I access the i member: v_strMyVector[i] == "xxxx"; ? (it works, though why?)
Do i always need to define an iterator to acces to go to the beginning of the vector, and lop on its members ?
What is the purpose of an iterator if I have access to all members of the vector directly (see 1)?
Thanks in advance,
Sun
It works only because there's no bounds checking for operator[], for performance reason. Doing so will result in undefined behavior. If you use the safer v_strMyVector.at(i), it will throw an OutOfRange exception.
It's because the operator[] returns a reference.
Since vectors can be accessed randomly in O(1) time, looping by index or iterator makes no performance difference.
The iterator lets you write an algorithm independent of the container. This iterator pattern is used a lot in the <algorithm> library to allow writing generic code easier, e.g. instead of needing N members for each of the M containers (i.e. writing M*N functions)
std::vector<T>::find(x)
std::list<T>::find(x)
std::deque<T>::find(x)
...
std::vector<T>::count(x)
std::list<T>::count(x)
std::deque<T>::count(x)
...
we just need N templates
find(iter_begin, iter_end, x);
count(iter_begin, iter_end, x);
...
and each of the M container provide the iterators, reducing the number of function needed to just M+N.
It returns a reference.
No,, because vector has random access. However, you do for other types (e.g. list, which is a doubly-linked list)
To unify all the collections (along with other types, like arrays). That way you can use algorithms like std::copy on any type that meets the requirements.
Regarding your second point, the idiomatic C++ way is not to loop at all, but to use algorithms (if feasible).
Manual looping for output:
for (std::vector<std::string>::iterator it = vec.begin(); it != end(); ++it)
{
std::cout << *it << "\n";
}
Algorithm:
std::copy(vec.begin(), vec.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
Manual looping for calling a member function:
for (std::vector<Drawable*>::iterator it = vec.begin(); it != end(); ++it)
{
(*it)->draw();
}
Algorithm:
std::for_each(vec.begin(), vec.end(), std::mem_fun(&Drawable::draw));
Hope that helps.
Workd because the [] operator is overloaded:
reference operator[](size_type n)
See http://www.sgi.com/tech/stl/Vector.html
Traversing any collection in STL using iterator is a de facto.
I think one advantage is if you replace vector by another collection, all of your code would continue to work.
That's the idea of vectors, they provide direct access to all items, much as regular arrays. Internally, vectors are represented as dynamically allocated, contiguous memory areas. The operator [] is defined to mimic semantics of the regular array.
Having an iterator is not really required, you may as well use an index variable that goes from 0 to v_strMtVector.size()-1, as you would do with regular array:
for (int i = 0; i < v_strMtVector.size(); ++i) {
...
}
That said, using an iterator is considered to be a good style by many, because...
Using an iterator makes it easier to replace underlying container type, e.g. from std::vector<> to std::list<>. Iterators may also be used with STL algorithms, such as std::sort().
std::vector is a type of sequence that provides constant time random access. You can access a reference to any item by reference in constant time but you pay for it when inserting into and deleting from the vector as these can be very expensive operations. You do not need to use iterators when accessing the contents of the vector, but it does support them.