C ++ STL에서 const_iterator와 non-const 반복자의 차이점은 무엇입니까?


139

a const_iterator와 an 의 차이점은 무엇 iterator이며 어디에서 다른 것을 사용합니까?


1
const_iterator라는 이름은 이터레이터가 const 인 것처럼 들리지만이 이터레이터가 가리키는 것은 실제 const입니다.
talekeDskobeDa

답변:


124

const_iterator지시하는 값을 변경할 수 없습니다 iterator.

C ++의 모든 것과 마찬가지로 const정기적 반복자를 사용해야하는 좋은 이유가없는 한 항상 선호하십시오 (즉 const, 지정된 값을 변경 하지 않는다는 사실을 사용하고 싶습니다 ).


8
완벽한 세상에서 그럴 것입니다. 그러나 C ++를 사용하는 const는 코드를 작성한 사람만큼 우수합니다. (
JaredPar

가변성은 매우 좋은 이유로 존재합니다. 거의 사용되지 않으며 Google 코드 검색을 살펴보면 유효 비율이 상당히 높습니다. 키워드는 매우 강력한 최적화 도구이며, 제거하면 const-correctness ( coughpointerscoughandcoughreferencescough )를 개선하는 것과 같지 않습니다
coppro

2
더 강력한 해킹처럼. 내가 'mutable'키워드를 사용한 것에 대해 지금까지 본 모든 사례 중에서 하나만 제외하고는 결함을 극복하기위한 해킹으로 코드가 잘못 작성되고 변경 가능하다는 정확한 지표였습니다.
John Dibling

7
const 클래스 내에서 긴 계산 결과를 캐싱하는 것과 같이 합법적 인 용도로 사용됩니다. 반면, 거의 20 년 동안 C ++ 개발에서 가변성을 사용한 유일한 시간입니다.
Geek

const_iterator를 사용하는 일반적인 예는 반복자가 rvalue 일 때입니다.
talekeDskobeDa

40

그들은 거의 자명해야합니다. 반복자가 T 유형의 요소를 가리키는 경우 const_iterator는 'const T'유형의 요소를 가리 킵니다.

기본적으로 포인터 유형과 같습니다.

T* // A non-const iterator to a non-const element. Corresponds to std::vector<T>::iterator
T* const // A const iterator to a non-const element. Corresponds to const std::vector<T>::iterator
const T* // A non-const iterator to a const element. Corresponds to std::vector<T>::const_iterator

const 반복자는 항상 같은 요소를 가리 키므로 반복자 자체 는 const입니다. 그러나 가리키는 요소는 const 일 필요는 없으므로 가리키는 요소를 변경할 수 있습니다. const_iterator는 const 요소를 가리키는 반복자이므로 반복자 자체를 업데이트 (예 : 증가 또는 감소) 할 수 있지만 가리키는 요소는 변경할 수 없습니다.


1
"const 반복자는 항상 같은 요소를 가리 킵니다."이것은 올바르지 않습니다.
John Dibling

2
어떻게 요? 밑줄이 누락되었습니다. const std :: vector <T> :: iterator 유형의 변수를 std :: vector <T> :: const_iterator와 대조하고 있습니다. 전자의 경우, 반복자 자체는 const이므로 수정할 수 없지만 참조하는 요소는 자유롭게 수정할 수 있습니다.
jalf

4
아, 알겠습니다 예, 누락 된 밑줄을 놓쳤습니다.
John Dibling

3
@JohnDibling const iterater과 (과) 의 미묘함을 설명해주었습니다 const_iterator.
legends2k

8

불행히도 STL 컨테이너의 많은 메소드 는 const_iterators 대신 반복자 를 매개 변수로 사용합니다. 따라서 const_iterator 가 있다면 "이 반복자가 가리키는 요소 앞에 요소를 삽입하십시오"라고 말할 수 없습니다 (이러한 것은 개념적으로 const 위반이 아니라고 생각합니다). 어쨌든 그것을 원한다면 std :: advance () 또는 boost :: next ()를 사용하여 비 const 반복자로 변환해야합니다 . 예 : boost :: next (container.begin (), std :: distance (container.begin (), the_const_iterator_we_want_to_unconst)) . 경우 컨테이너 A는 표준 : : 목록 , 그 호출에 대한 실행 시간이 될 것입니다 O (n)을 .

따라서 "논리적"인 곳에 const를 추가하는 보편적 인 규칙은 STL 컨테이너와 관련하여 덜 보편적입니다.

그러나 부스트 컨테이너는 const_iterator를 사용합니다 (예 : boost :: unordered_map :: erase ()). 부스트 컨테이너를 사용할 때 "const agressive"가 될 수 있습니다. 그건 그렇고, STL 컨테이너가 언제 고쳐질 지 아는 사람이 있습니까?


1
그것은 의견의 문제 일 수 있습니다. vector및 의 경우 deque하나의 요소를 삽입하면 기존의 모든 반복자가 무효화됩니다 const. 그러나 나는 당신의 요점을 봅니다. 이러한 작업은 const반복자가 아닌 컨테이너 기능 으로 보호됩니다 . 그리고 표준 컨테이너 인터페이스에 const-non-const 반복자 변환 함수가없는 이유가 궁금합니다.
Potatoswatter

당신은 올바른 Potatoswatter입니다, 나는 범주 적으로, 그것은 임의 접근 컨테이너와 container.begin () + (the_const_iterator_we_want_to_unconst – container.begin ())O (1) 입니다. 또한 비 랜덤 액세스 컨테이너에 변환 기능이없는 이유가 궁금하지만 그만한 이유가 있습니까? 비 랜덤 액세스 컨테이너의 함수가 const_iterators를 사용 하지 않는 이유가 있는지 알고 있습니까?
Magnus Andermo

"이러한 것을 말하는 것은 개념적으로 const 위반이 아니라고 생각합니다."-이것은 매우 흥미로운 의견이며, 주제에 대해 다음과 같은 생각을 가지고 있습니다. 간단한 포인터로, 하나는 말할 수 int const * foo; int * const foo;int const * const foo;세 자신의 방법으로 각각 유효하고 유용합니다. std::vector<int> const bar두 번째 것과 동일해야하지만 불행히도 종종 세 번째와 같이 취급됩니다. 문제의 근본 원인은 벡터에서 std::vector<int const> bar;와 같은 효과를 얻을 수있는 방법이 없다는 것을 말할 수 없다는 것 int const *foo;입니다.
dgnuff

5

가능하면 const_iterator를 사용하고 다른 선택이 없을 때는 iterator 를 사용하십시오 .


4

최소 실행 가능 예제

비 const 반복자를 사용하면 그들이 가리키는 것을 수정할 수 있습니다.

std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);

Const 반복자는하지 않습니다 :

const std::vector<int> v{0};
std::vector<int>::const_iterator cit = v.begin();
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;

상술 한 바와 같이 v.begin()되어 const과부하 및 반환하거나 iterator또는 const_iterator용기 변수 CONST 다움에 따라 :

const_iterator팝업이 나타나는 일반적인 경우 thisconst메서드 내에서 사용될 때 입니다 .

class C {
    public:
        std::vector<int> v;
        void f() const {
            std::vector<int>::const_iterator it = this->v.begin();
        }
        void g(std::vector<int>::const_iterator& it) {}
};

const하게 this만드는, CONST this->vCONST.

일반적으로로 잊어 버릴 수 auto있지만 반복자를 전달하기 시작하면 메소드 서명에 대해 반복자를 생각해야합니다.

const 및 non-const와 마찬가지로 non-const에서 const로 쉽게 변환 할 수는 있지만 다른 방법은 아닙니다.

std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();

// non-const to const.
std::vector<int>::const_iterator cit = it;

// Compile time error: cannot modify container with const_iterator.
//*cit = 1;

// Compile time error: no conversion from const to no-const.
//it = ci1;

사용할 것 : const intvs와 유사 int: const 반복자를 사용할 수있을 때마다 (컨테이너를 수정할 필요가없는 경우) constiterator를 선호하여 수정하지 않고 읽을 의도를 더 잘 문서화합니다.


0

(다른 사람들이 말했듯이) const_iterator를 사용하면 가리키는 요소를 수정할 수 없으며 const 클래스 메서드 내에서 유용합니다. 또한 의도를 표현할 수 있습니다.


0

이제 상수 반복자를 사용하지 않고 간단한 예제로 설명하겠습니다. 임의의 정수 컬렉션 "randomData"가 있다고 가정하겠습니다.

    for(vector<int>::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0;
for(vector<int>::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i;

컬렉션 내에서 데이터 쓰기 / 편집을 위해 볼 수 있듯이 일반 반복자가 사용되지만 읽기 목적으로 상수 반복기가 사용되었습니다. 첫 번째 for 루프에서 상수 반복자를 사용하려고하면 오류가 발생합니다. 일반적으로 상수 반복자를 사용하여 콜렉션 내부의 데이터를 읽습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.