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...
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
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.
Consider the following example:
vector<vector<char>*> *outer = new vector<vector<char>*>();
{
vector<char> *inner = new vector<char>();
inner->push_back(0);
inner->push_back(1);
inner->push_back(2);
outer->push_back(inner);
inner->push_back(3);
}
auto x = outer->at(0);
for (auto c : x) {
cout << c << ",";
}
I would like to iterate through the values of the vector<char>*; how can I accomplish that?
Why don't you simply dereference x?
for (auto c : *x) { // Here
cout << c << ",";
}
It will take *xby reference and, so, won't make a copy.
The type of x is vector<char>* so you need to iterate over what is pointed to by x; you need to dereference x.
for (auto&& c : *x) {
// ^ dereference the container for a range
// ^ note the use of &&
As a side note;
the characters for the integer values 0, 1 etc. are not printable, I'd test with 0x31 etc or just push back characters '0', '1' etc.
it is generally preferable to use auto&& in the range based for loops to avoid copies or subtle bugs when the container returns proxy object.
Here is a demonstrative program
#include <iostream>
#include <vector>
#include <cstring>
int main()
{
const char *s = "Hello Lu4";
std::vector<std::vector<char> *> *v =
new std::vector<std::vector<char> *>( 1, new std::vector<char>( s, s + std::strlen( s ) ) );
for ( char c : *( *v )[0] ) std::cout << c;
std::cout << std::endl;
for ( auto p : *v ) delete p;
delete v;
}
The program output is
Hello Lu4
Also you could use the following loop
for ( auto inner : *v )
{
for ( char c : *inner ) std::cout << c;
std::cout << std::endl;
}
If to use this loop in the demonstrative program you will get the same result as above because the "outer" vector contains only one element with index 0.
I have a pointer to a vector. Now, how can I read the contents of the vector through pointer?
There are many solutions, here's a few I've come up with:
int main(int nArgs, char ** vArgs)
{
vector<int> *v = new vector<int>(10);
v->at(2); //Retrieve using pointer to member
v->operator[](2); //Retrieve using pointer to operator member
v->size(); //Retrieve size
vector<int> &vr = *v; //Create a reference
vr[2]; //Normal access through reference
delete &vr; //Delete the reference. You could do the same with
//a pointer (but not both!)
}
Access it like any other pointer value:
std::vector<int>* v = new std::vector<int>();
v->push_back(0);
v->push_back(12);
v->push_back(1);
int twelve = v->at(1);
int one = (*v)[2];
// iterate it
for(std::vector<int>::const_iterator cit = v->begin(), e = v->end();
cit != e; ++cit)
{
int value = *cit;
}
// or, more perversely
for(int x = 0; x < v->size(); ++x)
{
int value = (*v)[x];
}
// Or -- with C++ 11 support
for(auto i : *v)
{
int value = i;
}
Do you have a pointer to a vector because that's how you've coded it? You may want to reconsider this and use a (possibly const) reference. For example:
#include <iostream>
#include <vector>
using namespace std;
void foo(vector<int>* a)
{
cout << a->at(0) << a->at(1) << a->at(2) << endl;
// expected result is "123"
}
int main()
{
vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
foo(&a);
}
While this is a valid program, the general C++ style is to pass a vector by reference rather than by pointer. This will be just as efficient, but then you don't have to deal with possibly null pointers and memory allocation/cleanup, etc. Use a const reference if you aren't going to modify the vector, and a non-const reference if you do need to make modifications.
Here's the references version of the above program:
#include <iostream>
#include <vector>
using namespace std;
void foo(const vector<int>& a)
{
cout << a[0] << a[1] << a[2] << endl;
// expected result is "123"
}
int main()
{
vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
foo(a);
}
As you can see, all of the information contained within a will be passed to the function foo, but it will not copy an entirely new value, since it is being passed by reference. It is therefore just as efficient as passing by pointer, and you can use it as a normal value rather than having to figure out how to use it as a pointer or having to dereference it.
vector<int> v;
v.push_back(906);
vector<int> * p = &v;
cout << (*p)[0] << endl;
You can access the iterator methods directly:
std::vector<int> *intVec;
std::vector<int>::iterator it;
for( it = intVec->begin(); it != intVec->end(); ++it )
{
}
If you want the array-access operator, you'd have to de-reference the pointer. For example:
std::vector<int> *intVec;
int val = (*intVec)[0];
There are a lot of solutions. For example you can use at() method.
*I assumed that you a looking for equivalent to [] operator.
vector <int> numbers {10,20,30,40};
vector <int> *ptr {nullptr};
ptr = &numbers;
for(auto num: *ptr){
cout << num << endl;
}
cout << (*ptr).at(2) << endl; // 20
cout << "-------" << endl;
cout << ptr -> at(2) << endl; // 20
The easiest way use it as array is use vector::data() member.