2008-09-11 4 views
28

저는 조금 떨어져서 오래된 멜론을 털어 내고 C++로 돌아 왔습니다.C++ (stl) 대 Java의 반복자는 개념적으로 차이가 있습니까?

Java Iterator는 hasNext(), next() 및 remove() 메소드가있는 컨테이너에 대한 인터페이스입니다. hasNext()가 있으면 에 컨테이너가 통과하는 한계 인이라는 개념이 있음을 의미합니다. C++ 표준 템플릿 라이브러리에서

//with an Iterator 
Iterator<String> iter = trees.iterator(); 
while (iter.hasNext()) 
{ 
    System.out.println(iter.next()); 
} 

는, 반복자는 == 데이터 형식 또는 클래스 지지대 연산자 ++ 및 연산자를 표현하기 위해 보이지만 을 가지고 다음에 진행하기 전에 너무 비교가 필요합니다 내장 제한의 개념이 없습니다 목. 이 제한은 사용자가 두 개의 반복자를 비교하는 경우 보통의 경우 두 번째 반복자가 컨테이너 끝임을 비교해야합니다.

vector<int> vec; 
vector<int>::iterator iter; 

// Add some elements to vector 
v.push_back(1); 
v.push_back(4); 
v.push_back(8); 

for(iter= v.begin(); iter != v.end(); iter++) 
{ 
    cout << *i << " "; //Should output 1 4 8 
} 

흥미로운 부분은 C++에서 포인터는 배열에 대한 반복자입니다. STL은 기존의 것을 가져 와서 컨벤션을 구축했습니다.

거기에 더 이상 미묘한 미묘함이 있습니까?

+0

당신은 꽤 많이 말했습니다. Java에서는 range와 iterator의 개념이 거의 병합되었습니다. C++에서 반복자는 그것이 속한 요소의 범위에 대한 개념이 없으며 실제로 여러 범위의 일부가 될 수 있습니다 (끝이 시작되고 끝이 1, 끝이 시작되고 끝이 3, 끝이 시작됨 + 6 등등.) – jalf

+0

"... 오래된 멜론에서 먼지를 뽑으려고"- 화려한 문구. – kevinarpe

답변

18

예, 개념적으로 큰 차이가 있습니다. C++은 다른 "클래스"의 반복자를 사용합니다. 일부는 임의 액세스 (Java와는 달리)에 사용되며, 일부는 순방향 액세스 (예 : java)에 사용됩니다. 다른 것들도 데이터 쓰기 (예 : transform과 함께 사용)에 사용됩니다.

  • 입력 반복자
  • 출력 반복자
  • 앞으로 반복자
  • 양방향 반복자
  • 임의 접근 반복자

이는 지금까지 :

C++ Documentation의 반복자 개념을 참조하십시오 더 많은 흥미롭고 강력한 Java/C#의 반복적 인 반복자에 비해. 바라건대 이러한 규칙은 C++ 0x 's Concepts을 사용하여 성문화 될 것입니다.

+0

Java 라이브러리에는 랜덤 액세스 및 양방향의 ListIterator가 있습니다. –

+1

"임의 액세스 및 양방향"은 모순입니다. ListIterator는 양방향이며 읽기 및 쓰기 액세스를 제공한다는 것을 의미합니다. –

+0

참고 : ListIterator에는 'bidirectional'의 모든 요구 사항이 포함되지 않습니다. 복사를 지원하지 않습니다. 즉, 나중에 다시 방문하도록 현재 위치를 저장할 수 없습니다. 별도의 답변을 참조하십시오. – Aaron

1

반복자는 배열의 내용을 순차적으로 반복하는 간단한 경우에만 포인터와 동일합니다. 반복자 (iterator)는 데이터베이스, 파일, 네트워크, 다른 계산 등에서 여러 가지 다른 소스의 객체를 제공 할 수 있습니다.

7

실제로 배열 요소에 대한 포인터는 배열의 반복자입니다.

Java에서 반복자는 기본 컨테이너에 대한 지식이 C++보다 많습니다. C++ 반복자는 일반적이며 쌍의 반복자는 컨테이너의 하위 범위, 여러 컨테이너 (http://www.justsoftwaresolutions.co.uk/articles/pair_iterators.pdf 또는 http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/zip_iterator.html 참조) 범위 또는 숫자 범위 (http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/counting_iterator.html 참조)

참조 범위를 나타낼 수 있습니다.

반복기 범주는 주어진 반복기에서 수행 할 수있는 작업과 수행 할 수없는 작업을 식별합니다.

19

아마도 조금 더 이론적입니다.수학적으로 C++의 콜렉션은 반복자의 반 개방 구간, 즉 콜렉션의 시작을 가리키는 하나의 반복자와 마지막 요소 인 바로 뒤의 을 가리키는 하나의 반복자로 설명 될 수 있습니다.

이 대회는 다양한 가능성을 열어줍니다. 알고리즘이 C++에서 작동하는 방식은 모두 더 큰 컬렉션의 하위 시퀀스에 적용될 수 있습니다. Java에서 이러한 작업을 수행하려면 다른 반복자를 리턴하는 기존 콜렉션 주위에 랩퍼를 작성해야합니다.

이터레이터의 또 다른 중요한 측면은 이미 Frank가 언급했습니다. 이터레이터에는 여러 가지 개념이 있습니다. Java 반복자는 C++의 입력 반복자에 해당합니다. 즉, 한 번에 한 단계 씩 증가 할 수 있고 뒤로 이동할 수없는 읽기 전용 반복자입니다.

다른 극단적으로 C++ 포인터와 정확히 일치하는 임의의 액세스 반복자 개념이 있습니다.

모두 C++은 C 포인터 또는 Java 반복기보다 훨씬 더 다양한 작업에 적용 할 수있는 훨씬 풍부하고 순수한 개념을 제공합니다.

+0

Java에는 ListIterator가있어 양방향으로 이동할 수 있습니다. – akuhn

+0

나는 이것이 오래된 대답이라는 것을 알고있다. 그러나 ... 1.Bi-directional은 그것이 앞뒤로 움직인다는 것을 의미한다. 2. 임의 액세스 란 임의의 비 순차적 ** 임의 ** 순서 (예 : 색인 액세스와 같은)로 요소에 액세스 할 수 있음을 의미합니다. 3. 읽기/쓰기 액세스는 전적으로 가변성이라고하는 다른 개념입니다. 읽기 전용 반복자는 앞으로 또는 뒤로 이동할 수 있습니다. 그것들은 두 개의 독립 변수입니다. 반복자를 이동하거나 다시 설정하고 반복자를 다시 사용하는 문제에 대해 더 많은 관심을 갖고 있습니다. Sun은 인터페이스와 관련된 명확한 사용법을 분명히 가지고 있지만 개발이 미흡한 것 같습니다. –

+1

@SinthiaV 흠. 나는이 논평을 어떻게해야할지 모르겠다. 나는 물론 이러한 구분을 알고 있고, 나의 대답에있는 어떤 것도 "input iterator"에 대해 이야기 할 때 C++ 개념을 사용한다는 사실을 제외하면이 개념은 실제로 읽기 전용 * 전달 *으로 모델화됩니다. 반복자). –

1

반복자는 포인터와 호환되도록 설계된 C++ 라이브러리 (이전의 STL 부분) 반복기입니다. 포인터 연산이없는 Java는 프로그래머에게 더욱 친숙해질 자유가있었습니다.

C++에서는 한쌍의 반복자를 사용해야합니다. 자바에서는 반복자 또는 컬렉션을 사용합니다. 반복자는 알고리즘과 데이터 구조 사이의 연결 고리입니다. 1.5+ 용으로 작성된 코드는 특정 알고리즘이나 데이터 구조 (프로그래머의 다양한 대다수는 필요하지 않음)를 구현하지 않는 한 반복자를 언급 할 필요가 거의 없습니다. Java가 동적 인 다형성 서브 세트 (polymorphism subset) 등을 다루기 때문에 핸들링이 훨씬 쉽습니다.

3

나에게 근본적인 차이점은 Java 반복자가 항목을 가리키는 반면 C++ STL 반복자는 항목을 가리킨다는 점입니다.

2

C++ 반복기는 포인터 개념을 일반화 한 것입니다. 그들은 더 넓은 범위의 상황에 적용 가능하게합니다. 이는 임의의 범위를 정의하는 것과 같은 일을하는 데 사용될 수 있음을 의미합니다.

자바 반복자는 비교적 멍청한 열거 자입니다 (C#만큼 나쁘지는 않지만 Java에는 ListIterator가 있으며 컬렉션을 변경하는 데 사용할 수 있음).

11

앞서 언급했듯이 Java 및 C# 반복자는 혼합 된 위치 (상태)와 범위 (값)를 설명하지만 C++ 반복자는 위치와 범위의 개념을 구분합니다. C++ 반복자는 '어디에서 갈 수 있습니까?'와는 별도로 '지금 어디에 있습니까?'를 나타냅니다.

Java 및 C# 반복기는 복사 할 수 없습니다. 이전 위치를 복구 할 수 없습니다. 일반적인 C++ 반복자가 할 수 있습니다.

this example을 고려

// for each element in vec 
for(iter a = vec.begin(); a != vec.end(); ++a){ 
    // critical step! We will revisit 'a' later. 
    iter cur = a; 
    unsigned i = 0; 
    // print 3 elements 
    for(; cur != vec.end() && i < 3; ++cur, ++i){ 
     cout << *cur << " "; 
    } 
    cout << "\n"; 
} 

프로그램 출력을 볼 수있는 위의 링크를 클릭합니다.

이 다소 어리석은 루프는 3 개의 요소로 구성된 인접한 각 하위 시퀀스를 정확히 한 번 (그리고 마지막에 짧은 시퀀스 두 개를 연속적으로) 인쇄하면서 시퀀스를 통과합니다 (순방향 반복기 의미론 만 사용). 그러나이 알고리즘은 O (N * M) 반복자 증분과 O (1) 공간이 될 것입니다.

Java 스타일 반복자는 위치를 독립적으로 저장할 수있는 기능이 없습니다.당신은 하나

  • 만들고, 당신은
  • 목록의 N 시간을 통과해야합니다 반복 역사를 저장하기 위해 (예를 들어) O를 M 사이즈의 배열을 사용하여, O (1) 공간을 잃게됩니다 (N^2 + N * M) 시간
  • 을 사용하거나 GetAt 멤버 함수, 제네릭 손실 및 연결된 목록 컨테이너 유형을 사용할 수있는 구체적인 Array 유형을 사용하십시오.

이 예에서는 정방향 반복 메커니즘 만 사용되었으므로 no problems으로 목록을 바꿀 수있었습니다. 이는 검색, 지연된 초기화 및 평가, 정렬 등과 ​​같은 일반 알고리즘을 작성하는 데 중요합니다.

상태를 유지할 수없는 것은 매우 적은 알고리즘이 구축 된 C++ STL 입력 반복기에 가장 밀접하게 관련됩니다.

+0

예,하지만 유용한 알고리즘은 무엇입니까! std :: find (_if), std :: count 및 std :: copy는 많은 중요한 코드의 기초입니다. –

+0

이 예는 부당합니다. 자바와 C++에서 작동하는'= 연산자'에 의존합니다. C++에서는 객체의 사본을 새 객체 (얕은 스냅 샷)로 수행하고 Java (및 C#)에서는 참조를 복사하므로 두 변수가 모두 동일한 객체에서 작동합니다. C++의 복사 동작은 위의 구문을 사용하여'a'에 영향을 미치지 않고'cur'을 향상시킬 수 있음을 의미합니다. Java 또는 C#에서는 기본 반복자가 수정됩니다.'clone()'을 사용하면 Java에서 동일한 동작을 할 수 있습니다. – BeeOnRope

1

차이점에 대해 많은 좋은 답변이 있지만 Java 반복기에서 가장 괴롭히는 것이 강조되지 않았다는 것을 느꼈습니다. 현재 값을 여러 번 읽을 수는 없습니다. 이는 특히 반복자를 병합 할 때 많은 시나리오에서 유용합니다.

C++에서 이터레이터를 진행하고 현재 값을 읽는 방법이 있습니다. 그 가치를 읽는 것은 반복을 발전시키지 않습니다. 그래서 당신은 그것을 여러 번 읽을 수 있습니다. 이것은 Java 반복자에서는 불가능하며,이를 위해 래퍼를 작성합니다.

사이드 노트 : 래퍼를 만드는 쉬운 방법 중 하나는 이미 존재하는 것을 사용하는 것입니다 - 구아바의 PeekingIterator.

+0

사실입니다. Java iterators는 현재 값을 검색하고 범위를 벗어나면 테스트합니다. 이상적으로는 분리되어 구별되어야합니다. – beldaz