iterator vs const_iterator
Modern C++에 적응하기
Effective Modern C++ Chapter 3. iterator vs const_iterator
iterator vs const_iterator
const
를 사용하는 것이 의미가 있는 경우에는 항상 const
를 사용하는 것이 바람직하다. iterator
도 마찬가지이다.
C++98에서 const_iterator
는 사용하기가 상당히 까다로웠다.
먼저 non-const
컨테이너로부터 const_iterator
를 얻는 간단한 방법이 없었다.
1 | typedef std::vector<int>::iterator IterT; |
values
는 int
(non-const
)타입의 데이터를 저장하는 컨테이므로, values.begin()
과 values.end()
은 iterator
를 반환한다.
std::find
함수에서 데이터 수정이 발생하지 않을 것이므로 iterator
보다는 const_iterator
를 인자로 전달하는 것이 의미론적으로 옳을것이다.
그렇기 때문에 std::find
에 const_iterator
를 전달하기 위해서 캐스팅이 필요하다.
C++98에서 STL 컨테이너의 삽입(insert
), 삭제(erase
)함수는 인자로 오직 iterator
만 사용할 수 있었다.
1 | values.insert(static_cast<IterT>(ci), 1998); // error |
C++11에 들어서 두 함수가 const_iterator
를 지원하기 시작했지만, const_iterator
에서 iterator
로의 적절한 변환이 존재하지 않는다.
C++11 에서는 const_iterator
에 대한 편의성이 많이 개선되었다.
먼저 컨테이너가 직접 const_iterator
를 반환하는 멤버함수 cbegin()
과 cend()
를 제공한다.
그리고 위에서 언급했듯이 STL 컨테이너의 삽입, 삭제 함수들이 const_iterator
를 지원한다.
1 | std::vector<int> values; |
C++14에서는 비멤버 함수 cbegin()
과 cend()
도 표준에 추가되었다.(rbegin()
, rend()
, crbegin()
, crend()
와 함께)
1 | template <typename C, typename V> |
위 템플릿 함수가 C++11에서도 동작하게 하기위해 직접 비멤버 cbegin()
과 cend()
를 구현할 수 있다.
C++11에서 직접 구현한 비멤버 cbegin()
은 아래와 같다.
1 | template <typename C> |
템플릿 매개변수 C
에 일반적인 STL 컨테이너가 전달되었다면, 함수 매개변수 container
는 해당 컨테이너의 const
참조로 연역된다.
그리고 그런 컨테이너에 비멤버 begin
을 호출하면 const_iterator
가 반환된다.
이 템플릿 함수는 STL 컨테이너 뿐만 아니라 내장 배열에 대해서도 잘 동작한다.
비멤버 begin
은 이러한 내장배열에 특수화 되어있는데, 배열의 원소를 가리키는 포인터를 반환한다.
이 경우에 container
는 const
배열에 대한 참조로 연역된다. const
배열의 원소는 const
이므로, std::begin
은 const
를 가리키는 포인터를 반환한다.
References
iterator vs const_iterator
https://joyusgim.github.io/2022/07/26/iterator-vs-const-iterator/