2

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?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Ashish M
  • 119
  • 8
  • 3
    You should do `vector::iterator ptr= vec3.begin()` or, better yet `auto ptr= vec3.begin()` – Mirko Sep 10 '19 at 16:14
  • 3
    And even better: `for (auto& el: vec3) { cout << el << ' '; }` – Mirko Sep 10 '19 at 16:15
  • Thanks for replying @Mirko . I know these methods but i was wondering why can't we give it first element reference and iterate over the array. – Ashish M Sep 10 '19 at 16:17
  • 1
    Possible dup: https://stackoverflow.com/questions/30950285/iterator-pointer-or-what-is-it/30950304#30950304 – Marshall Clow Sep 10 '19 at 16:20
  • 3
    You can, but not mixing things. `&vec3[a]` is not an iterator. It's an `int*`. You can't compare it to `end()` either; you should do: `for (int* ptr= &vec3[0]; ptr != &vec3[vec3.size()]; ptr++)` or something along those lines – Mirko Sep 10 '19 at 16:22
  • Thanks for clarification @Mirko – Ashish M Sep 10 '19 at 16:29
  • 5
    @Mirko Technically, it _is_ a kind of iterator ... it's just not the same kind of iterator as `vector::iterator` ;) – Lightness Races in Orbit Sep 10 '19 at 16:36

2 Answers2

7

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;
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

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...

JFMR
  • 23,265
  • 4
  • 52
  • 76