Существует ли законный способ преобразовать const_iterator в iterator?
Подскажите, пожалуйста, возможно ли законно преобразовать const_iterator в iterator ? Проблема следующая: Я пишу индексатор, в публичном интерфейсе которого фигурирует хэндл, который имеет тип std::list<. >::const_iterator . Это сделано для того, чтобы внешний код мог самостоятельно использовать данный итератор для вызова константных методов (геттеров) того, на что указывает итератор данного типа. Например:
class Object < // . public: size_t GetField() const < return field; >private: size_t key; size_t field; >; class Indexator < public: using Handle = std::list::const_iterator; Handle GetObjectByKey(const size_t key) const < // . >>;
Но я также хочу, чтобы внешний код смог поменять неиндексируемые поля, пускай и через использование методов Indexer . Например так:
void Indexator::SetField(Handle handle) < std::list::iterator iterator = (cast?) handle; iterator->field = . ; >
Существует ли законный способ преобразовать const_iterator в iterator ?
Const iterator c что это
Доброго времени суток.
Зачем нужен сonst_iterator в STL. Может потому что контейнер не может изменить данные под итератором?
Re: const_iterator
От: | AlexanderVX | |
Дата: | 06.06.12 00:18 | |
Оценка: | 3 (1) +1 -1 |
Здравствуйте, Nizumi, Вы писали:
N>Доброго времени суток.
N>Зачем нужен сonst_iterator в STL. Может потому что контейнер не может изменить данные под итератором?
IMHO для того, чтобы STL могла создавать итераторы, которые полностью предотвращают запись в объект по указателю итератора, а не просто с модификатором const C++. Современные OS позволяют накладывать атрибут read-only на регион памяти. То есть, получили const_iterator, и всё честно, гарантированно по нему нельзя писать, только перебирать. Особенно ценное свойство для разработки библиотек и компонентов для других разработчиков (когда доверие пользователю кода ограничено).
Re: const_iterator
От: | Сыроежка | |
Дата: | 06.06.12 00:58 | |
Оценка: | 4 (2) +1 |
Здравствуйте, Nizumi, Вы писали:
N>Доброго времени суток.
N>Зачем нужен сonst_iterator в STL. Может потому что контейнер не может изменить данные под итератором?
Чтобы можно было работать с константными контейнерами.
Представьте себе, что вы написали функцию, которая выводит на консоль содержимое контейнера. Очевидно, что вы этой функции будете передавать свой контейнер не по значению, а по ссылке, причем константной ссылке. Например, для вектора вы могли бы написать
template
void display( const std::vector &v );
Какой итератор вы можете использовать в теле этой функции? Очевидно, что только const_iterator, так как объект v является константным.
Меня можно встретить на www.cpp.forum24.ru
Re: const_iterator
От: | sdf | |
Дата: | 06.06.12 00:59 | |
Оценка: |
Здравствуйте, Nizumi, Вы писали:
N>Доброго времени суток.
N>Зачем нужен сonst_iterator в STL. Может потому что контейнер не может изменить данные под итератором?
* если вам передали параметром константный указатель/ссылку на коллекцию.
* если у вас есть коллекция — член класса, а текущий выполняемый метод класса итерируется по ней и имеет модификатор const
В этих случаях использовать неконстантный итератор нельзя.
Re[2]: const_iterator
От: | Сыроежка |
Дата: | 06.06.12 01:03 |
Оценка: |
Кстати сказать, это одна из распространеных ошибок программистов, когда они объявляют параметр как константную ссылку на контейнер, а затем внутри функции начинают писать что-то вроде следующее:
for ( typename std::vector::iterator it = v.begin(); it != v.end(); ++it )
< /*. */ >
Меня можно встретить на www.cpp.forum24.ru
Re[3]: const_iterator
От: | dilmah |
Дата: | 06.06.12 02:45 |
Оценка: |
С>Кстати сказать, это одна из распространеных ошибок программистов, когда они объявляют параметр как константную ссылку на контейнер, а затем внутри функции начинают писать что-то вроде следующее:
С>for ( typename std::vector::iterator it = v.begin(); it != v.end(); ++it )
С> < /*. */ >
немножко не понял..
это же не скомпилируется, так?
Значит, этого не может быть в чужом коде, который ты смотрел, так?
Откуда же ты тогда знаешь, что это распространенная ошибка?
Или есть компиляторы, которые это компилируют?
Re: const_iterator
От: | Vain | google.ru |
Дата: | 06.06.12 02:47 | |
Оценка: |
Здравствуйте, Nizumi, Вы писали:
N>Доброго времени суток.
N>Зачем нужен сonst_iterator в STL. Может потому что контейнер не может изменить данные под итератором?
Итератор обычно реализован через указатель на данные, а в стл если контейнер стал или был константным, то не только его нельзя изменять (добавлять/удалять элементы), но ещё нельзя и сами данные изменять. Следовательно, нужен новый тип итератора.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[2]: const_iterator
От: | johny5 | https://www.facebook.com/TachyonWars/ |
Дата: | 06.06.12 04:24 | |
Оценка: |
Здравствуйте, Сыроежка, Вы писали:
С>template
С>void display( const std::vector &v );
С>Какой итератор вы можете использовать в теле этой функции? Очевидно, что только const_iterator, так как объект v является константным.
Можно теперь подумать над вопросом, почему мы завели цельный новый тип вместо использования
typedef iteratorconst T> const_iterator;
Re[3]: const_iterator
От: | sdf | |
Дата: | 06.06.12 04:59 | |
Оценка: |
Здравствуйте, johny5, Вы писали:
J>Здравствуйте, Сыроежка, Вы писали:
С>>template
С>>void display( const std::vector &v );
С>>Какой итератор вы можете использовать в теле этой функции? Очевидно, что только const_iterator, так как объект v является константным.
J>Можно теперь подумать над вопросом, почему мы завели цельный новый тип вместо использования
J>
J>typedef iteratorconst T> const_iterator; J>
Потому что тип итератора определяется не типом элемента контейнера, а типом самого контейнера (итератору нужен доступ к готовому типу контейнера)
в итогде получается как-то так:
vectorclass T> < typedef _vector_iterator_impl < vector> iterator; typedef _const_vector_iterator_impl < vector> const_iterator; >
на практике iterator может являтьсянаследником const_iterator
Iterator library
Iterators are a generalization of pointers that allow a C++ program to work with different data structures (for example, containers and ranges (since C++20) ) in a uniform manner. The iterator library provides definitions for iterators, as well as iterator traits, adaptors, and utility functions.
Since iterators are an abstraction of pointers, their semantics are a generalization of most of the semantics of pointers in C++. This ensures that every function template that takes iterators works as well with regular pointers.
Contents
- 1 Iterator categories
- 2 Definitions
- 2.1 Types and writability
- 2.2 Dereferenceability and validity
- 2.3 Ranges
- 2.3.1 Comparable range
- 2.3.2 Counted range
- 7.1 Indirect callable concepts
- 7.2 Common algorithm requirements
- 7.3 Utilities
[edit] Iterator categories
Instead of being defined by specific types, each category of iterator is defined by the operations that can be performed on it. This definition means that any type that supports the necessary operations can be used as an iterator — for example, a pointer supports all of the operations required by LegacyRandomAccessIterator , so a pointer can be used anywhere a LegacyRandomAccessIterator is expected.
All of the iterator categories (except LegacyOutputIterator ) can be organized into a hierarchy, where more powerful iterator categories (e.g. LegacyRandomAccessIterator ) support the operations of less powerful categories (e.g. LegacyInputIterator ). If an iterator falls into one of these categories and also satisfies the requirements of LegacyOutputIterator , then it is called a mutable iterator and supports both input and output. Non-mutable iterators are called constant iterators.
Iterators are called constexpr iterators if all operations provided to meet iterator category requirements are constexpr functions.
Note: A type supporting the required operations in a row of the table above does not necessarily fall into the corresponding category, see the category page for the complete list of requirements.
[edit] Definitions
[edit] Types and writability
An input iterator i supports the expression * i , resulting in a value of some object type T , called the value type of the iterator.
An output iterator i has a non-empty set of types that are writable (until C++20) indirectly_writable (since C++20) to the iterator; for each such type T , the expression * i = o is valid where o is a value of type T .
For every iterator type X for which equality is defined (until C++20) , there is a corresponding signed integer (until C++20) integer-like (since C++20) type called the difference type of the iterator.
[edit] Dereferenceability and validity
Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding sequence. Such a value is called a past-the-end value.
Values of an iterator i for which the expression * i is defined are called dereferenceable. The standard library never assumes that past-the-end values are dereferenceable.
Iterators can also have singular values that are not associated with any sequence. Results of most expressions are undefined for singular values; the only exceptions are
- the assignment of a non-singular value to an iterator that holds a singular value,
- destroying an iterator that holds a singular value, and,
- for iterators that meet the DefaultConstructible requirements, using a value-initialized iterator as the source of a copy or move (since C++11) operation.
In these cases the singular value is overwritten the same way as any other value. Dereferenceable values are always non-singular.
An invalid iterator is an iterator that may be singular.
[edit] Ranges
Most of the standard library’s algorithmic templates that operate on data structures have interfaces that use ranges.
An iterator j is called reachable from an iterator i if and only if there is a finite sequence of applications of the expression ++ i that makes i == j . If j is reachable from i , they refer to elements of the same sequence.
A range is a pair of iterators that designate the beginning and end of the computation. A range [ i , i ) is an empty range; in general, a range [ i , j ) refers to the elements in the data structure starting with the element pointed to by i and up to but not including the element pointed to by j .
Range [ i , j ) is valid if and only if j is reachable from i .
A range is either
- a comparable range [ i , s ) , an iterator i and a sentinel s that designate the beginning and end of the computation ( i and s can have different types), or
- a counted range i + [ 0 , n ) , an iterator i and a count n that designate the beginning and the number of elements to which the computation is to be applied.
Comparable range
An iterator and a sentinel denoting a range are comparable. [ i , s ) is empty if i == s ; otherwise, [ i , s ) refers to the elements in the data structure starting with the element pointed to by i and up to but not including the element, if any, pointed to by the first iterator j such that j == s .
A sentinel s is called reachable from an iterator i if and only if there is a finite sequence of applications of the expression ++ i that makes i == s .
If s is reachable from i , [ i , s ) denotes a valid range.
Counted range
A counted range i + [ 0 , n ) is empty if n == 0 ; otherwise, i + [ 0 , n ) refers to the n elements in the data structure starting with the element pointed to by i and up to but not including the element, if any, pointed to by the result of n applications of ++ i .
A counted range i + [ 0 , n ) is valid if and only if
- n == 0 ; or
- all of the following conditions are satisfied:
- n is positive,
- i is dereferenceable, and
- ++ i + [ 0 , — n ) is valid.
The result of the application of functions in the standard library to invalid ranges is undefined.
[edit] Iterator concepts
C++20 introduces a new system of iterators based on concepts that are different from C++17 iterators. While the basic taxonomy remains similar, the requirements for individual iterator categories are somewhat different.
std:: string::begin
If the string object is const-qualified, the function returns a const_iterator. Otherwise, it returns an iterator.
Member types iterator and const_iterator are random access iterator types (pointing to a character and to a const character, respectively).
Example
1
2
3
4
5
6
7
8
9
10
11
12
13// string::begin/end int main () < std::string str ("Test string"); for ( std::string::iterator it=str.begin(); it!=str.end(); ++it) std::cout '\n'; return 0; >
Test string
Complexity
Unspecified.
Iterator validity
Generally, no changes.
On some implementations, the non-const version may invalidate all iterators, pointers and references on the first access to string characters after the object has been constructed or modified.Data races
The object is accessed, and in some implementations, the non-const version modifies it on the first access to string characters after the object has been constructed or modified.
The iterator returned can be used to access or modify characters.Complexity
Unspecified, but generally constant.
Iterator validity
No changes.
Data races
The object is accessed (neither the const nor the non-const versions modify it).
The iterator returned can be used to access or modify characters. Concurrently accessing or modifying different characters is safe.Exception safety
No-throw guarantee: this member function never throws exceptions.
The copy construction or assignment of the returned iterator is also guaranteed to never throw.See also
string::end Return iterator to end (public member function) string::rbegin Return reverse iterator to reverse beginning (public member function)