티스토리 뷰

const_iterator iterator 와 달리 수정하면 안 되는 값들을 가리킨다. 표준 관행에 따르면 가능한 한 항상 const 를 사용하라는 말에 따라 가능하다면 const_iterator 를 사용하는 것이 좋다. 예시를 보면서 이해해보도록 하자.

std::vector<int> values;
...
std::vector<int>::iterator it = 
    std::find(values.begin(), values.end(), 1983);

values.insert(it, 1998);

 위의 코드는 1983 이라는 값을 찾아 그 위치에 1998 이라는 값을 삽입하는 코드이다. 여기서 주목해야할 점은 find 함수로 찾은 iterator 를 직접 수정하는 일은 없다는 것이다. 이것을 표준 관행에 따르도록 하면 iterator const_iterator 로 바꾸는 것이 옳을 것이다.

C++98

그러나 C++98 에서는 쉽지가 않았다. const_iterator 를 얻을 방법이 없었기 때문이다. const_iterator 를 얻으려면 다음과 같이 작성해야한다.

typedef std::vector<int>::iterator IterT;
typedef std::vector<int>::const_iterator ConstIterT;

std::vector<int> values;
...
ConstIterT ci =
    std::find(static_cast<ConstIterT>(values.begin()),
              static_cast<ConstIterT>(values.end()),
              1983);
              
values.insert(static_cast<IterT>(ci), 1998); // 컴파일이 안될 수도 있다.

 const_iterator 를 얻기 위해서는 정적 캐스팅을 이용해야만 했으며, insert 를 할 때에는 const_iterator 를 허용하지 않아 다시 iterator 로 캐스팅을 해야만 했다. 그럼에도 불구하고 컴파일조차 되지 않는 경우가 있다. const_iterator 에서 iterator 로 캐스팅을 허용하지 않기 때문이다. 

C++11

 C++11에서는 아주 간단해졌다. cbegin(), cend() 함수는 const_iterator 를 반환해주며, insert end const_iterator 를 사용한다.

std::vector<int> values;
...
auto it =
    std::find(values.cbegin(), values.cend(), 1983);

values.insert(it, 1998);

그러나 아쉽게도 generic 을 사용하는 곳에서는 C++11 도 문제가 발생한다.

template<typename C, typename V>
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);
                       
    container.insert(it, insertVal);
}
                  

 위의 코드는 C++14 에서는 문제없이 동작하지만 C++11 에서는 동작하지 않는다. C++11 표준화 과정에서 비멤버 cbegin cend 를 빼먹고 추가하지 않았기 때문이다. 아래와 같이 비멤버 cbegin 을 작성할수 있다.

template <class C>
auto cbegin(const C& container)->decltype(std::begin(container))
{
    return std::begin(container);
}

여기서 멤버 cbegin 이 아닌 비멤버 begin 을 사용하는데 이해가 가지 않을 수 있다. 그 이유는 container 파라미터를 보면 const 로 선언되어 있는 것을 볼 수 있다. std::begin const container에 대해 const_iterator 를 반환하도록 되어 있기 때문이다.

 

참고 서적

스콧 마이어스, Effective Modern C++

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함