본문 바로가기
C++/Effective Modern C++

iterator보다는 const_iterator를

by COCO1337 2020. 7. 6.

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를 선호하라

반응형

댓글