const_iterator는 const를 가리키는 포인터의 STL 버전이다. 반복자가 가리키는 것을 수정할 필요가 없을때에는 항상 const_iterator를 사용하는 것이 바람직하다.
C++98까지는 삽입, 삭제 위치를 iterator로만 지정할 수 있었다. 왜곡된 방법을 사용해서라도 const_iterator를 얻어도 정작 삽입, 삭제에 사용할 수 없기 때문에 사용할 수가 없었다. 하지만 C++11부터는 컨테이너 멤버함수로 cbegin과 cend가 추가되었고, 이는 const_iterator를 돌려준다.
C++11에서 const_iterator를 사용하는 방법은 다음과 같다.
std::vector<int> values;
...
auto it = std::find(values.cbegin(), values.cend(), 1983); // cbegin과 cend 사용
values.insert(it, 1998);
일반성을 극대화한 코드는 특정 멤버 함수의 존재 대신 그 멤버 함수에 상응하는 비멤버 함수를 사용한다.
C++11 표준화 과정에서 비멤버 함수 begin과 end는 표준에 추가했지, cbegin, cend, rbegin, rend, crbegin, crend는 추가하지 않았다. 하지만 간단하게 구현할 수 있다.
template<typename C, typename V> // C++14 버전
void findAndInsert(C& container, const V& targetVal, const V& insertVal);
{
using std::cbegin;
using std::cend;
auto it = std::find(cbegin(container), cend(container), targetVal); // 비멤버 cbegin, cend
container.insert(it, insertVal);
}
// C++11에서 비멤버 함수인 cbegin 구현
template <class C>
auto cbegin(const C& container)->decltype(std::begin(container))
{
return std::begin(container);
}
이 cbegin 템플릿은 자료구조를 대표하는 임의의 인수 형식 C를 받고, 해당 const 참조 매개변수 container를 통해 자료구조에 접근한다. 통상적인 컨테이너 형식에 대해 container는 그 컨테이너의 const버전에 대한 참조(예시, const std::vector<int>&)가 된다. 이 const 컨테이너에 대해 비멤버 begin 함수를 호출하면 const_iterator 형식의 반복자가 반환된다.
내장 배열 형식인 경우에도 const 배열의 원소들은 const이므로 const 배열에 대해 비멤버 begin이 돌려주는 포인터는 const를 가리키는 포인터이다.
Conclusion
- iterator 보다 const_iterator를 선호하라
- 최대한 일반적인 코드에서는 begin, end, rbgin 등의 비멤버 버전들을 해당 멤버 변수보다 선호하라
Reference
Effective Modern C++ 항목 13: iterator보다 const_iterator를 선호하라
'C++ > Effective Modern C++' 카테고리의 다른 글
가능하면 항상 constexpr을 사용하라 (0) | 2020.07.08 |
---|---|
예외를 방출하지 않을 함수는 noexpect로 (0) | 2020.07.07 |
재정의 함수들은 override로 (0) | 2020.07.05 |
정의되지 않은 비공개 함수보다는 삭제된 함수를 (0) | 2020.07.03 |
범위 없는 enum 보다 범위 있는 enum으로 (0) | 2020.07.02 |
댓글