0

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

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • "In my school textbook" wow. [Consider getting a better one](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – T.C. Oct 26 '16 at 21:42
  • `std::list` does not have a random access iterator like e.g. `std::vector` – ProXicT Oct 26 '16 at 21:42
  • If the school textbook had this line: ***list::iterator i = 0;*** I agree you need a better book.. – drescherjm Oct 26 '16 at 21:43
  • drescherjm: Everything in the textbook has been fine up to now. – Dr Negative Oct 26 '16 at 21:46
  • 1
    Note that this will not work even with vector (like "`vector::iterator i = 0`") – EmDroid Oct 26 '16 at 21:52
  • 2
    Geez guys, it was just a typo, I don't think that warrants the "get a better book" comments, especially since we don't even know what book is actually being used. Just remove the `= 0` from the iterator declaration and move on. – Remy Lebeau Oct 26 '16 at 22:49

3 Answers3

3

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.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • 1
    You are right, however, you did not explain why `0` may not be a valid value for an iterator. If I am not mistaken, is it because `std::list` does not have random access iterator unlike from e.g. `std::vector`? – ProXicT Oct 26 '16 at 21:45
  • As far as I can tell, an integer is not a valid value for (any) iterator, because to construct an iterator, you need to somehow refer the original structure (where you get the iterator from). And this is clearly not the case with a simple integer. (or of course without arguments you create an invalid empty iterator) – EmDroid Oct 26 '16 at 21:48
  • 1
    There may not be a constructor or assignment operator that takes an integer value. – Thomas Matthews Oct 26 '16 at 21:49
  • According to cppreference.com, the [`std::list::iterator`](http://en.cppreference.com/w/cpp/container/list) only has to satisfy the *Bidirectional Iterator* interface. – Thomas Matthews Oct 26 '16 at 21:59
  • 1
    The code in the book may have been tested on an old compiler and library in which the list::iterator was a typedef for some sort of pointer. In that case, 0 would have been ok and synonymous to the null pointer. – Klitos Kyriacou Oct 26 '16 at 22:17
  • @KlitosKyriacou: it makes sense that a `std::vector` iterator might be implemented using a raw pointer to the vector data, but a `std::list` iterator could never be implemented as a raw pointer, since pointer arithmetic on a list node pointer would not iterate the list correctly (unless the nodes are stored in contiguous memory, which `std::list` is not guaranteed to use). Iteration requires access to each node's inner pointers, and so a list iterator would have to use a specialized class to handle the `++` and `--` operators correctly. – Remy Lebeau Oct 26 '16 at 22:59
  • @RemyLebeau you have a point - list::iterator wouldn't be a pointer. – Klitos Kyriacou Oct 27 '16 at 01:08
2

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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
1

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:

  1. Return the object it's currently "pointing" to (using the * operator)
  2. 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:

  1. * dereferences the pointer stored in vector<int>::iterator and returns its value.
  2. ++ 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.