Background: Ubuntu OS is installed on my machine, gcc version is 5.4.0. I can freely call the erase method (for a variable of type std::vector , for example) passing it the const_iterator parameter to the item to be deleted. On the other machine, the same Ubuntu OS is installed, but gcc version 4.8.4 is installed - and, as I understand it, in this version (although it supports compilation with the std=c++11 flag), the erase method erase accepts an iterator .

In general, the code looks like this:

 void SomeoneClass::method( ... ) { Subscribers::const_iterator pos = anotherMethod( ... ); if( pos != m_subscribers.end() ) { m_subscribers.erase( pos ); } } 

I decided to add a check for the version of gcc being used, sort of

 #if defined( __GNUC__ ) && ( __GNUC__ < 5 ) // тут получаем номер элемента через pos и т.д #else Subscribers::const_iterator pos = anotherMethod( ... ); if( pos != m_subscribers.end() ) { m_subscribers.erase( pos ); } #endif 

There were questions:

  1. Am I right to do this comparison: const_iterator pos != container.end() ?
  2. How to get an element number through const_iterator, and then get an iterator using this number? (remember, gcc 4.8) Something like this:

 Subscribers::difference_type itemPos = pos - m_subscribers.begin(); Subscribers::iterator it = m_subscribers.begin() + itemPos; 

UPD: I beg your pardon. We consider not std::vector , but std::list

  • For all containers, the behavior of the iterators for const transformation is the same. - aleks.andr
  • @ aleks.andr, thank you, you answered my main question. As for the moment why I indicated a specific container - this is the 2nd question, and here the implementation, I think, will depend on the type of container. - isnullxbh

2 answers 2

In the standard C ++ library, it is possible to get a const_iterator object from an iterator .

Most likely (not strong in the implementation details), the constructor const_iterator<T>(iterator<T>) {...} not used like this, but note: the inverse transformation ( iterator<T>(const_iterator<T>) ) is not allowed .

So in the code

 const_iterator pos != container.end() 

the end() iterator is implicitly converted to a constant iterator.

Sample program:

 #include <vector> #include <iostream> using namespace std; int main(int /*argc*/, char** /*argv*/) { vector<int> v; v.resize(5); vector<int>::iterator it = v.begin(); // получаем итератор vector<int>::const_iterator ct = v.begin(); // получаем константный итератор cout << "it == ct ? " << (it == ct ? "True" : "False") << endl; // сравниваем константный итератор с неконстантным (it будет приведён в const_iterator) vector<int>::const_iterator ct2 = it; // получаем константный итератор из неконстантного cout << "ct2 == begin() ? " << (ct2 == v.begin() ? "True" : "False") << endl; // сравниваем константный итератор с неконстантным (begin() будет приведён в const_iterator) cout << "it == const begin() ? " << (it == const_cast<const vector<int>&>(v).begin() ? "True" : "False") << endl; // сравниваем константный итератор с неконстантным (it будет приведён в const_iterator) // а вот так сделать уже не получится: // vector<int>::iterator it2 = ct; // попытаемся получить неконстантный итератор из константного return 0; } 

UPD: In the c++11 standard, functions were added to the containers to get const_iterator without additional conversions:

 // замените container на нужный вам конкретный тип: const_iterator container.cbegin() const_iterator container.cend() 

    As far as I know, in C ++ 2003 you could use only non-constant iterators with the erase method. In C ++ 2011, this situation was changed, and it became possible to call the erase method with constant iterators.

    The member function of the erase class erase not constant, and therefore it does not matter which iterator is passed to it. The iterator only specifies the position of the element to be deleted. The element itself is not modified using this iterator.

    Compare. You can dynamically create a constant object. For example,

     const int *pi = new int( 10 ); 

    But as you create it, you can delete it using the same pointer with the const qualifier.

     delete pi; 

    Another thing would be if you tried to modify the created object using this pointer, such as

     *pi = 20; 

    then the compiler would give an error message, since you cannot change a constant object.

    You can compare constant and non-constant iterators, since a non-constant iterator can be implicitly converted to a constant iterator.

    As for the question

    How to get an element number through const_iterator, and then get an iterator using this number? (remember, gcc 4.8) Something like this:

    then there is a standard function std::distance declared in the header <iterator> , which allows you to calculate the position, having an iterator. For example, if you have a list

     std::list<int> lst { 1, 2, 3, 4, 5 }; 

    and found an element with a value of 3 , using the standard algorithm std::find

     auto it = std::find( lst.begin(), lst.end(), 3 ); 

    then you can determine the position of the found item in the list as follows

     auto pos = std::distance( lst.begin(), it ); 

    However, for containers that do not have random access iterators, as is the case with the standard std::list container, this operation is not effective. It's just that the function will go through the entire list in succession until it reaches the specified iterator. It may look like this.

     std::list<int>::size_type pos = 0; for ( auto current = lst.begin(); current != it; ++current ) { ++pos; } 

    Having a starting iterator and a given position, you can get the corresponding position iterator using the std::advance functions or the std::next and std::prev functions, which are also declared in the <iterator> header.

    For example, having the initial iterator and the pos position calculated earlier, you can get the it iterator, as follows

     auto it = std::next( lst.begin(), pos ); 

    However, you must be careful when calling this function, since it does not check whether the value of the pos variable is correct, and whether the iterators will not be out of range for a given container.

    • Thanks, plus set. As for the erase method - I wrote why I have to use these transformations - the gcc 4.8 implementation allows calling erase only with an iterator& type parameter. - isnullxbh
    • @isnullxbh Usually, all new changes in the standard of the C ++ language are introduced by compilers gradually, and this can take even years. :) - Vlad from Moscow
    • And yet, it takes years to get some comrades to install new software versions :) - isnullxbh