일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 보편 참조
- Smart Pointer
- 게임
- iterator
- 상속
- 영화
- UE4
- more effective c++
- 암시적 변환
- 참조자
- 반복자
- lua
- virtual function
- operator new
- universal reference
- reference
- 예외
- c++
- Effective c++
- implicit conversion
- resource management class
- exception
- effective modern c++
- 언리얼
- effective stl
- 영화 리뷰
- 스마트 포인터
- std::async
- 오블완
- 티스토리챌린지
Archives
- Today
- Total
스토리텔링 개발자
[Effective Modern C++] 13. const_iterator 선호하기 본문
Effective C++/Effective Modern C++
[Effective Modern C++] 13. const_iterator 선호하기
김디트 2025. 2. 21. 10:57728x90
항목 13. iterator보다 const_iterator를 선호하라
const_iterator
- const_iterator는 수정하면 안되는 값들을 가리킨다.
- 가능한 한 const를 사용하라는 표준 관례는 반복자에도 적용된다.
- 허나 C++98에서는 이게 쉽지 않았다.(EC++ 항목 26 참조)
std::vector<int> values;
...
std::vector<int>::iterator it = std::find(values.begin(), values.end(), 1983);
values.insert(it, 1998);
- 위 코드에서의 반복자는 전혀 수정되지 않으므로 const_iterator면 좋겠다.
- 하지만 C++98에서는 간단하지 않다.
typedef std::vector<int> 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); // 컴파일이 안 될 수 있다.
- static_cast를 사용하여 다소 작위적인 코드가 되었다.
- 비 const 컨테이너로부터 const_iterator를 얻는 간단한 방법 없기 때문이다.
- C++98에서는 삽입 / 삭제 위치를 iterator로만 지정할 수 있으므로 iterator로 다시 캐스팅해야 했다.
- 허나 const_iterator에서 iterator로의 이식성 있는 변환은 존재하지 않으므로 컴파일 에러가 발생한다.
C++11에서의 const_iterator
- 얻고 사용하기 쉬워졌다.
- 컨테이너 멤버 함수 cbegin, cend는 const_iterator를 돌려준다.
- 삽입, 삭제 위치를 지정 STL 멤버 함수들이 이제는 const_iterator도 받는다.
std::vector<int> values;
...
auto it = std::find(values.cbegin(), values.cend(), 1983); // cbegin / cend 사용
values.insert(it, 1998);
- 최대한 범용적인 라이브러리 코드(maximally generic)를 작성할 때는 문제가 있다.
- begin, end 함수들을 비멤버 함수로 제공해야 하는 컨테이너들이 존재한다는 점을 고려하기 때문이다.
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); // 비멤버 cbegin / cend 사용
container.insert(it, insertVal);
}
- 위 코드는 C++14에선 동작하지만. C++11에선 안된다.
- 비멤버 begin, end만 존재하기 때문이다.
- 아래처럼 직접 구현해주는 게 어렵진 않다.
template<class C>
auto cbegin(const C& container)->decltype(std::begin(container))
{
return std::begin(container); // 멤버 cbegin을 호출하지 않고 구현?
}
- 매개변수로 들어온 컨테이너가 const &에 std::begin를 사용하면 const_iterator 타입이 리턴된다.
- 멤버 cbegin을 사용하지 않고 구현한 덕분에 cbegin이 없는 컨테이너에 대해서도 동작한다.
- 기본 배열 타입에 대해서도 동작한다.
- 이 경우 const 배열에 대한 참조가 된다.
- C++11의 비멤버 begin엔 기본 배열 타입 템플릿 특수화 버전이 존재한다.
728x90
'Effective C++ > Effective Modern C++' 카테고리의 다른 글
[Effective Modern C++] 15. constexpr (0) | 2025.02.25 |
---|---|
[Effective Modern C++] 14. noexcept (0) | 2025.02.24 |
[Effective Modern C++] 12. override 키워드와 참조 한정사(reference qualifier) (0) | 2025.02.20 |
[Effective Modern C++] 11. 삭제된 함수(deleted function) (0) | 2025.02.19 |
[Effective Modern C++] 10. enum class (0) | 2025.02.18 |
Comments