티스토리 뷰
[Effective Modern C++] 항목 13. iterator보다 const_iterator를 선호하라
pppgod 2019. 10. 20. 15:33const_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++
'C++ > Effective Modern C++' 카테고리의 다른 글
[Effective Modern C++] 항목 15. 가능하면 항상 constexpr을 사용하라 (0) | 2019.10.29 |
---|---|
[Effective Modern C++] 항목 14. 예외를 방출하지 않을 함수는 noexcept로 선언하라 (0) | 2019.10.20 |
[Effective Modern C++] 항목 12. 재정의 함수들을 override로 선언하라 (0) | 2019.10.07 |
[Effective Modern C++] 항목 11. 정의되지 않은 비공개 함수보다 삭제된 함수를 선호하라 (0) | 2019.10.07 |
[Effective Modern C++] 항목 10. 범위 없는 enum보다 범위 있는 enum을 선호하라 (0) | 2019.09.28 |
- Total
- Today
- Yesterday
- 발아시기
- MOVE
- Unreal
- auto
- C
- C++11
- Forwarding
- Effective
- 다이소
- Override
- Future
- C++14
- Effective Modern C++
- detach
- Join
- C++
- 보편 참조
- forward
- async
- std::move
- std::forward
- 포인터
- CPP
- Modern
- 람다
- const
- Overloading
- Perfect
- 보편참조
- thread
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |