In the C++ Standard Map Library, a call to the iteration functions returns an iterator pointer,
std::map<int, int> map;
std::map<int, int>::iterator ite = map.find(1);
But, when the iterator is used, it must be accessed as a pointer variable,
int first = ite->first;
int second = ite->second;
Why is this the case when we are putting the obtained value from the find function into a non-pointer. Shouldn't the correct syntax be:
std::map<int, int>::iterator *pIte = map.find(1)
or if using the original syntax,
int first = ite.first;
int second = ite.second;
since we are obtaining a value, and not a pointer from the function's return value? It is also not clarified in the documentation. Why is this the case?
As #jaggedSpire suggested, iterators are supposed to act like ptrs, having defined the operators *, ->, etc. But the thing is, an iterator isn't an explicit pointer. The syntax you suggested:
std::map<int, int>::iterator *pIte = map.find(1);
Is a pointer to an iterator, not just an iterator. The reason when you wrote:
std::map<int, int>::iterator pIte = map.find(1);
you have to write: ite->first is because operator-> is defined for iterators. This means that iterators are supposed to act like pointers.
The call of the function
std::map<int, int>::iterator ite = map.find(1);
returns iterator that behaves like pointers.
So you need to use the syntax of accessing objects using pointers
int first = ite->first;
int second = ite->second;
Or you could write instead
int first = ( *ite ).first;
int second = ( *ite ).second;
Compare for example
#include <iostream>
#include <iterator>
#include <algorithm>
#include <utility>
int main()
{
const size_t N = 5;
std::pair<int, int> a[N] = { { 2, 2 }, { 4, 4 }, { 1, 1 }, { 3, 3 }, { 5, 5 } };
std::pair<int, int> *it = std::find( std::begin( a ), std::end( a ), std::make_pair( 1, 1 ) );
if ( it != std::end( a ) )
{
std::cout << it - a << ": "
<< "{ " << it->first << ", " << it->second << " }" << std::endl;
}
return 0;
}
The program output is
2: { 1, 1 }
Here it is explicitly declared like a pointer.
Related
I would like to know if it is possible to access the elements of std::vector<std::vector<int>> via iterators: I cannot understand why this won't compile:
#include<vector>
#include<iostream>
std::vector<std::vector<int>> vec {{1,2},{3,4}} ;
// to access the single vector
auto it = vec.begin() ;
// to access the element of the vector
auto iit = it.begin() ;
Here the error I get:
prova.cpp: In function ‘int main()’:
prova.cpp:10:15: error: ‘class __gnu_cxx::__normal_iterator<std::vector<int>*, std::vector<std::vector<int> > >’ has no member named ‘begin’
10 | auto iit = it.begin() ;
You can get an iterator to the inner elements from a reference to the inner vector. An iterator is not a reference to the element, but you have to dereference it. Change this:
// to access the element of the vector
auto iit = it.begin() ;
To
auto iit = it->begin();
Don't overcomplicate stuff. You iterate a vector like this:
std::vector<T> vect;
for (auto it = vect.begin(); it != vect.end(); ++it) {
auto& element = *it;
// element is a reference to the element in the vector
}
or with a range based loop:
for (auto& element : vect) {
// element is a reference to the element in the vector
}
It really never gets more complicated than that.
When you have a nested vector and you want to iterate elements of the inner vectors you just need to first get elements of the outer vector, then elements of the inner ones:
std::vector<std::vector<T>> vect2;
for (auto& inner_vector : vect2) {
// inner_vector is reference to element of vect2
for (auto& element : inner_vector) {
// element is reference to element of inner vector
}
}
auto iit = it.begin();
doesn't compile because it is an iterator, not a vector. You should use the overloaded value-of operator to get the vector pointed to by it.
auto iit = (*it).begin();
Then you can use the iterators as normal.
You can also use range-based for-loops:
for(auto &row : vec) {
for(auto &col : row) {
// do things
}
}
Iterators in particularly random access iterators simulate the behavior of pointers.
For example if you have an object of a class like:
struct A
{
int x;
} a = { 10 };
and a pointer to the object:
A *pa = &a;
then to access data members of the object using the pointer you need to write for example either:
std::cout << pa->x << '\n';
or:
std::cout << ( *pa ).x << '\n';
So consider this declaration:
auto it = vec.begin();
as a declaration of a pointer.
So using this iterator you can gets iterators of stored vectors like
auto iit1 = it->begin() ;
auto iit2 = ( ++it )->begin();
Using this approach you can write nested for loops to output the vector.
Here is a demonstration program:
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>> vec { { 1, 2 }, { 3, 4 } };
for ( auto it = vec.cbegin(); it != vec.cend(); ++it )
{
for ( auto iit = it->cbegin(); iit != it->cend(); ++iit )
{
std::cout << *iit << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
return 0;
}
The program output is:
1 2
3 4
I have used member functions cbegin and cend instead of begin and end to show that the vector is not being changed within the loops.
To do the same it is simpler to use the range-based for loop. For example:
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>> vec { { 1, 2 }, { 3, 4 } };
for (const auto &v : vec )
{
for ( const auto &item :v )
{
std::cout << item << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
return 0;
}
The program output is the same as shown above.
In the range-based for loop the compiler itself dereferences the iterators instead of you.
If you really want to use iterators the following code would do the job.
#include<vector>
#include<iostream>
int main()
{
std::vector<std::vector<int>> vec {{1,2},{3,4}} ;
for (auto it = vec.cbegin(); it != vec.cend(); ++it)
{
for (auto iit = it->cbegin(); iit != it->cend(); ++iit)
{
std::cout << "elem: " << *iit << "\n";
}
}
}
Otherwise, by all means use ranged for loops.
#include<vector>
#include<iostream>
int main()
{
std::vector<std::vector<int>> vec {{1,2},{3,4}} ;
for (const auto& inner_vec : vec)
{
for (const auto& elem : inner_vec)
{
std::cout << "elem: " << elem << '\n';
}
}
}
According to Cplusplus
An iterator is any object that, pointing to some element in a range of
elements (such as an array or a container)
vector <int> v = {0,1,2};
auto it = v.begin();
// it is a iterator pointing to the first element of the vector
// To access the first element, we will use *it
cout << *it; // will output 0
// Notice how * is used to get the value where it points at
In your case, vec is a vector of vectors. Where each element of vec is itself a vector. Each element of v defined in the above code snippet was an int.
std::vector<std::vector<int>> vec {{1,2},{3,4}} ;
// it is an iterator pointing to the elements of vec
// Notice that it points to the elements of vec
// Each element of vec is a vector itself
// So it "points" to a vector
auto it = vec.begin() ;
// to access the element of the vector
//auto iit = it.begin() ;
// To access the elements (which are int) of the vector, you need to use:
auto iit = (*it).begin();
// *it is the value where it points to (which is basically the first vector )
Another way to iterate over vec would be to use for each loop
for(auto v : vec)
{
for(int a : v)
{
cout<<a;
// a is an integer
}
}
I have used a nested for-loop to carry out insertion sort on a C++ STL <vector>. The first for-loop is over an iterator and the second one, over a reverse_itr.
I need to pass the index (iterator pointer value) from the first loop to the second. I have tried the following approach but it gives me this error
error: no match for ‘operator!=’ (operand types are
‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’ and
‘std::vector<int>::reverse_iterator’ {aka
‘std::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >’})
void insertionSort(int size, vector<int> arr) {
for(auto itr = arr.begin(); itr != arr.end() - 1; ++itr) {
int element = *(itr + 1);
cout << "Element being compared with preceding sub-array is : " << element << endl;
for(auto r_itr = (itr + 1); r_itr != arr.rend(); ++r_itr) {
if(*(r_itr+1) <= element) {
*r_itr = element;
break;
}
else {
*r_itr = *(r_itr+1);
}
}
}
}
I searched up quite a lot online, found a way to convert a reverse iterator to an iterator (using itr.base()) but not the other way round.
Also I am new to C++ STL and algorithms, please feel free to suggest any way to improve my code with respect to the "clean"-ness of code or the algorithm itself!
The class template std::vector has random access iterators. So there is no any need to convert a given "forward" iterator to a "reverse" iterator.
Just use with iterators the operator -- instead of the operator ++ or vice versa where it is required.
Pay attention to that the parameter size is not used in your function declared like
void insertionSort(int size, vector<int> arr);
If you want to sort a range from a vector then use two parameters declared as iterators that specify a range.
For example
void insertionSort( std::vector<int>::iterator first, std::vector<int>::iterator last );
Or you can write a more general function for vectors of any types using templates.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <cstdlib>
#include <ctime>
void insertionSort( std::vector<int>::iterator first, std::vector<int>::iterator last )
{
if ( first != last )
{
for ( auto current = first; ++current != last; )
{
typename std::iterator_traits<decltype( current )>::value_type
value( *current );
auto prev = current, next = current;
while ( next != first && value < *--prev )
{
*next-- = *prev;
}
if ( next != current ) *next = value;
}
}
}
int main()
{
std::vector<int> v;
const int N = 10;
std::srand( ( unsigned int )std::time( nullptr ) );
std::generate_n( std::back_inserter( v ), N, [=]{ return std::rand() % N; } );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
insertionSort( std::begin( v ), std::end( v ) );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
return 0;
}
Its output might look like
0 6 6 7 4 3 4 6 6 1
0 1 3 4 4 6 6 6 6 7
Try changing it to for(vector<int>::reverse_iterator r_itr(next(itr)); r_itr != arr.rend(); ++r_itr)
To expand on their working, reverse_iterator is not implemented the same as iterator. The logical and physical address for an iterator are the same but for reverse_iterator, the logical and physical address are not the same. For example: s.end() and s.rbegin() have the same physical address but *s.end() will give you an error but *s.rbegin() will give you the last value of the container s.
The code below will make things clear:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> S{ 1, 2, 3 };
set<int>::iterator itr = S.find(2);
cout << *itr << endl;
set<int>::reverse_iterator r_itr(itr);
cout << *r_itr << endl;
cout << itr._Ptr << ' ' << r_itr.base()._Ptr << endl;
//S.erase(r_itr); // ERROR!
S.erase(r_itr.base());
for (int e : S)
cout << e << ' ';
}
On my machine, it produced the following output:
2
1
00F85DA8 00F85DA8
1 3
I am trying to parse this simple array from the reference of its first element.
Here is my code:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
vector<int> vec3 { 1,2,3,4,5};
for( vector<int>::iterator ptr = &vec3[0]; ptr != vec3.end(); ++ptr )
{
cout << *ptr << " ";
}
}
But I am getting this error:
[Error] conversion from '__gnu_cxx::__alloc_traits<std::allocator<int> >::value_type* {aka int*}' to non-scalar type 'std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}' requested
What's the problem?
Iterators of the class std::vector are not necessary pointers (though they can be defined such a way and indeed some old implementations of the class std::vector defined its iterators as pointers.). They usually are defined as classes.
And the compiler error says that there is no implicit conversion from the type value_type * to the type of the iterator.
So in general you have to write
vector<int> vec3 { 1,2,3,4,5};
for( vector<int>::iterator ptr = vec3.begin(); ptr != vec3.end(); ++ptr )
{
cout << *ptr << " ";
}
However in this particular case you could use the range-based for statement.
vector<int> vec3 { 1,2,3,4,5};
for ( const auto &item : vec3 )
{
cout << item << " ";
}
If you indeed want to deal with pointers then the loop can look for example the following way
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vec3 { 1, 2, 3, 4, 5 };
for( auto ptr = vec3.data(); ptr != vec3.data() + vec3.size(); ++ptr )
{
std::cout << *ptr << ' ';
}
std::cout << '\n';
return 0;
}
Let vec be an object of type std::vector<int>, then vec.end() returns an std::vector<int>::iterator which can be different from the corresponding raw pointer, int *. One of the reasons for this would be to allow support for debugging and error checking (e.g., out-of-boundaries access).
As a consequence, you must write &(*vec.begin()) to obtain the address of the first element of the vector instead of just vec.begin() since the latter doesn't necessarily return a raw pointer.
You can easily check whether or not &vec[0] and vec.end() have the same type on your implementation:
auto a = vec.end();
auto b = &vec[0];
static_assert(std::is_same<decltype(a), decltype(b)>::value, "not same type");
In my case:
error: static_assert failed "not same type"
static_assert(std::is_same<decltype(a), decltype(b)>::value...
I am trying to delete an element in a vector of Objects. The vector is filled with instances of Object and at some point, I want to remove a certain element in a vector not by index, but by the element itself.
A simple example would be:
std::vector< string > strVector;
strVector.push_back( "abc" );
strVector.push_back( "def" );
strVector.push_back( "ghi" ); // So strVector should contain "abc", "def", and "ghi"
How do I remove "ghi" from that vector? Note that I don't know where "ghi" is in that vector.
// Something like this. Assume strVector = [ "abc", "cba", "ccb", "bac", "aaa" ]
strVector.removeElement( "ccb" );
A more relevant example to what I a working on:
class MyClass {
std::vector< Object > myObjVector;
void main( ARGS ) {
for ( int i = 0; i < 10; i++ ) {
Object myObject = Object( );
myObjVector.push_back( myObject );
}
int j = getANumber( ); // j could be any number within the size of the vector
Object myOtherObject = myObjectVector.at( j );
// How do I erase myOtherObject (which is an object inside the vector) ?
removeFromVector( myOtherObject );
}
}
I hope the question's clear. Thanks in advance.
EDIT: I figured it out, thanks to all those who answered. The trick was to give the class something unique that identifies it (like a name or a tag, as long as they are guaranteed to be unique) then use the erase-remove idiom to remove the object from the array.
If your use-case has no duplicates, then you are better off using an std::set and using the std::set::erase which takes a value.
std::set< string > strSet;
strSet.insert( "abc" );
strSet.insert( "def" );
strSet.insert( "ghi" );
strSet.insert( "ccb" );
strSet.erase("ccb");
If you need to cope with duplicates, then you have to specify the desired behaviour of the removal. Should it remove one or all of the elements matching a value? Do you care about preserving the order of the remaining elements? If you require using a vector, then lokk at the erase-remove idiom. But note that std::vector::erase has linear time complexity, whereas the relevant variant of std::set::erase has logarithmic time complexity. And erase-remove would remove all elements equal to the given value.
Note: if you want to use an std::set for a user defined type, you must provide either a less-than bool operator<(const UserType&) const or a comparison function or functor, implementing strict weak ordering.
If you must use a vector, then use erase(remove()):
#include <algorithm>
#include <string>
#include <vector>
strVector.erase(std::remove(strVector.begin(), strVector.end(), "ghi"),
strVector.end());
this will remove all instances of "ghi" from strVector.
If the objects in the vector support equality, and that's the condition
for removal, then you can use:
v.erase( std::remove( v.begin(), v.end(), "ghi" ), v.end() );
Otherwise, you'll need remove_if, with a functional object (or lambda,
if you have C++11) which returns true if the element is to be removed.
#include <iostream>
#include <vector>
class Object
{
public:
Object(int n){secret_num = n;}
virtual ~Object(){}
int getSecretNum(){return secret_num;}
private:
int secret_num;
};
int main()
{
int index= -1;
Object *urobj = new Object(104);
std::vector<Object*> urvector;
for(int i = 0; i < 10; ++i)
{
Object *obj = new Object(i+1);
urvector.push_back(obj);
}
urvector.push_back(urobj);
for(int j = 0; j < urvector.size(); ++j)
{
Object *tmp = urvector.at(j);
std::cout << tmp->getSecretNum() << std::endl;
if(urobj == tmp)
index = j;
}
if(index == -1)
std::cout << " not match " << std::endl;
else
std::cout << " match " << index << std::endl;
return 0;
}
Is it possible to access the std::for_each iterator, so I can erase the current element from an std::list using a lambda (as below)
typedef std::shared_ptr<IEvent> EventPtr;
std::list<EventPtr> EventQueue;
EventType evt;
...
std::for_each(
EventQueue.begin(), EventQueue.end(),
[&]( EventPtr pEvent )
{
if( pEvent->EventType() == evt.EventType() )
EventQueue.erase( ???Iterator??? );
}
);
I've read about using [](typename T::value_type x){ delete x; } here on SO, but VS2010 doesn't seem to like this statement (underlines T as error source).
You are using the wrong algorithm. Use remove_if:
EventQueue.remove_if([&](EventPtr const& pEvent)
{
return pEvent->EventType() == evt.EventType();
});
The STL algorithms do not give you access to the iterator being used for iteration. This is in most cases a good thing.
(In addition, consider whether you really want to use std::list; it's unlikely that it is the right container for your use case. Consider std::vector, with which you would use the erase/remove idiom to remove elements that satisfy a particular predicate.)
no, use a regular for instead.
for( auto it = EventQueue.begin(); it != EventQueue.end(); ++it )
{
auto pEvent = *it;
if( pEvent->EventType() == evt.EventType() )
it = EventQueue.erase( it );
);
Erase is not the only time you may need to know iterator from lambda.
To do this in a more general way, I am using & operator (implicit conversion to iterator) like this :
int main (int argc, char* argv []) {
size_t tmp [6] = {0, 1, 2, 3, 4, 5};
std::list<size_t> ls ((size_t*)tmp, (size_t*) &tmp [6]);
//printing next element
std::for_each ((const size_t*)tmp, (const size_t*) &tmp [5], [] (const size_t& s) {
std::cout << s << "->";
std::cout << *(&s +1) << " ";
});
std::cout << std::endl;
}