'for'루프를 사용하여 C ++ 벡터를 반복


140

저는 C ++ 언어를 처음 사용합니다. 나는 벡터를 사용하기 시작했으며 모든 코드에서 인덱스를 통해 벡터를 반복하는 것으로 보았을 때 for루프 의 첫 번째 매개 변수 는 항상 벡터를 기반으로하는 것입니다. Java에서는 ArrayList를 사용하여 이와 같은 작업을 수행 할 수 있습니다.

for(int i=0; i < vector.size(); i++){
   vector[i].doSomething();
}

C ++에서 이것을 볼 수없는 이유가 있습니까? 나쁜 습관입니까?


1
for 루프는 함수가 아니므로 매개 변수 (또는 인수, 전달하는 인수)가 없습니다. std::vector<int>::size_type i = 0;그래도 같은 의미 std::vector<int>::iterator it = vector.begin();입니까?
chris

정확히, 내가 본 모든 예제는 그런 식으로 작성되었습니다.
플린

4
Java에서는 for-each 루프를 선호하거나 반복자를 사용합니다. 약간 다른 구문이지만 C ++과 거의 동일합니다.
Jesse Good


10
여기서 대부분의 대답은 Q를 다음과 같이 잘못 가정합니다. 반복하는 가장 좋은 방법은 무엇입니까 std::vector? , 여기에 묻는 실제 Q는 다음과 같습니다 .C ++에서 이것을 볼 수없는 이유가 있습니까? 나쁜 습관입니까? aka 왜 반복하는 동안 반복자를 사용하는 C ++ 코드가 항상 표시 std::vector됩니까?
Alok 저장

답변:


92

C ++에서 이것을 볼 수없는 이유가 있습니까? 나쁜 습관입니까?

아니요. 나쁜 습관은 아니지만 다음 방법으로 코드를 확실하게 만듭니다. 유연성을 부여 수 있습니다.

일반적으로 C ++ 11 이전의 컨테이너 요소를 반복하는 코드는 다음과 같은 반복자를 사용합니다.

std::vector<int>::iterator it = vector.begin();

코드가 더 유연 해지기 때문입니다.

모든 표준 라이브러리 컨테이너는 반복자를 지원하고 제공합니다. 나중에 개발 시점에서 다른 컨테이너로 전환해야하는 경우이 코드를 변경할 필요가 없습니다.

참고 : 가능한 모든 표준 라이브러리 컨테이너에서 작동하는 코드를 작성하는 것이 쉽지 않은 것 같습니다.


25
누구 든지이 특별한 사례 / 코드 스 니펫에서 반복자에게 색인 작성에 대해 조언하는 이유를 설명해 주시겠습니까? 당신이 말하는이 "유연성"은 무엇입니까? 개인적으로 반복자를 좋아하지 않고 동일한 효과를 위해 입력 할 문자가 더 많습니다. 특히를 사용할 수없는 경우 auto.
Violet Giraffe

8
@VioletGiraffe : 반복자를 사용하는 동안 빈 범위와 같은 특정 경우에 잘못되기 어렵고 코드가 더 장황합니다. 물론 문제 또는 인식과 선택이므로 끝없이 토론 할 수 있습니다.
Alok 저장

9
왜 반복자를 선언하는 방법 만 보여 주지만 루프를 수행하는 데 사용하지 않는 이유는 무엇입니까?
underscore_d

116

이러한 관행을 보지 못하는 이유는 상당히 주관적이며 명확한 대답을 할 수 없습니다 iterator. 스타일 코드가 아닌 언급 된 방식을 사용하는 많은 코드를 보았 기 때문 입니다.

사람들 vector.size()이 반복 방법을 고려하지 않는 이유는 다음 과 같습니다.

  1. size()루프 조건에서 매번 호출하는 것에 대해 편집증이 됩니다. 그러나 문제가 아니거나 사소하게 수정 될 수 있습니다.
  2. 루프 자체 std::for_each()보다 선호for
  3. 나중에에서 컨테이너를 변경 std::vector다른 하나 (예에 map, list때문에하지 모든 컨테이너 지원, 또한 루프 메커니즘의 변화를 요구할 것이다) size()반복의 스타일

C ++ 11은 컨테이너를 통해 이동할 수있는 좋은 기능을 제공합니다. 이를 "range based for loop"(또는 Java에서 "enhanced for loop")라고합니다.

작은 코드로 전체를 통과 할 수 있습니다 (필수!) std::vector:

vector<int> vi;
...
for(int i : vi) 
  cout << "i = " << i << endl;

12
루프를 기반 으로하는 범위 의 작은 단점에 주목 하면됩니다 #pragma omp parallel for.
liborm

2
읽을 코드가 적기 때문에 컴팩트 버전이 마음에 듭니다. 일단 정신 조정을하면 이해하기가 훨씬 쉽고 버그가 더 두드러집니다. 또한 더 큰 코드 덩어리가 있기 때문에 비표준 반복이 발생하면 훨씬 더 명확합니다.
Code Abominator

87

벡터를 반복하는 가장 깨끗한 방법은 반복자를 사용하는 것입니다.

for (auto it = begin (vector); it != end (vector); ++it) {
    it->doSomething ();
}

또는 (위와 동일)

for (auto & element : vector) {
    element.doSomething ();
}

C ++ 0x 이전에는 auto를 반복자 유형으로 바꾸고 전역 함수 시작 및 종료 대신 멤버 함수를 사용해야합니다.

이것은 아마도 당신이 본 것입니다. 언급 한 접근 방식과 비교할 때 장점은 유형에 크게 의존하지 않는다는 것입니다 vector. vector다른 "컬렉션 유형"클래스로 변경 하면 코드가 여전히 작동합니다. 그러나 Java에서도 비슷한 작업을 수행 할 수 있습니다. 개념적으로 큰 차이는 없습니다. 그러나 C ++은 템플릿을 사용하여이를 구현합니다 (Java의 제네릭과 비교). 따라서 접근하는 모든 종류의 작동 beginend도 같은 정적 배열과 같은 비 클래스 유형에 대해 정의되는 함수. 여기를 참조하십시오. 일반 배열에서 범위 기반은 어떻게 작동합니까?


5
자동, 무료 시작 / 끝도 C ++ 11입니다. 또한 많은 경우에 ++ it 대신 ++ it를 사용해야합니다.
ForEveR

네 말이 맞아. 구현 begin하고 end, 그러나, 한 줄입니다.
JohnB

@JohnB는 고정 크기 배열에서도 작동하기 때문에 하나 이상의 라이너입니다. auto반면에 까다로울 것입니다.
juanchopanza

벡터에만 필요한 경우 하나의 라이너입니다.
JohnB

그럼에도 불구하고 첫 번째 예제는 C ++ 03에서는 작동하지 않기 때문에 오해의 소지가 있습니다.
juanchopanza

35

올바른 방법은 다음과 같습니다.

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    it->doSomething();
 }

여기서 T는 벡터 내부의 클래스 유형입니다. 예를 들어 클래스가 CActivity 인 경우 T 대신 CActivity를 작성하십시오.

이 유형의 방법은 모든 STL에서 작동합니다 (벡터뿐만 아니라 조금 더 좋습니다).

여전히 인덱스를 사용하려는 경우 방법은 다음과 같습니다.

for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
    v[i].doSomething();
}

std::vector<T>::size_type항상 그렇지 는 size_t않습니까? 그것이 제가 항상 사용하는 유형입니다.
Violet Giraffe

1
@VioletGiraffe 나는 당신이 옳다고 확신하지만 (실제로 확인하지는 않았지만) std :: vector <T> :: size_type을 사용하는 것이 좋습니다.
DiGMi

8

반복자를 사용해야하는 몇 가지 강력한 이유가 있습니다. 그 중 일부는 여기에 언급되어 있습니다.

나중에 컨테이너를 전환해도 코드가 무효화되지 않습니다.

즉, std :: vector에서 std :: list 또는 std :: set으로 이동하면 포함 된 값을 얻기 위해 숫자 인덱스를 사용할 수 없습니다. 반복자를 사용하는 것은 여전히 ​​유효합니다.

유효하지 않은 반복의 런타임 캐치

루프 중간에 컨테이너를 수정하면 다음에 반복기를 사용할 때 잘못된 반복자 예외가 발생합니다.


1
예제 코드로 위의 요점을 설명하는 기사 / 게시물을 가리킬 수 있습니까? 좋을 것입니다! 또는 : 하나를 추가 할 수 있다면 :
Anu

5

정수 인덱스가있는 배열을 반복하면 잘못된 인덱스가있는 배열을 첨자하여 잘못된 코드를 쉽게 작성할 수 있다고 언급 한 사람은 아무도 없습니다. 예를 들어, ij인덱스를 사용하여 중첩 루프 가있는 경우 배열을 잘못 첨자 j하지 않고 i프로그램에 오류 가 발생할 수 있습니다 .

반대로, 여기에 나열된 다른 형식, 즉 범위 기반 for루프 및 반복자는 오류가 덜 발생하기 쉽습니다. 언어 시맨틱과 컴파일러의 유형 검사 메커니즘은 잘못된 인덱스를 사용하여 실수로 배열에 액세스하는 것을 방지합니다.


4

STL을 사용하면 프로그래머는 iterators컨테이너를 통과하는 데 사용 합니다. 반복자는 모든 표준 컨테이너에 구현 된 추상 개념이기 때문입니다. 예를 들어 std::list전혀 없습니다 operator [].


3

자동 연산자를 사용하면 데이터 유형과 벡터 크기 또는 다른 데이터 구조에 대해 걱정할 필요가 없으므로 사용하기가 정말 쉽습니다.

자동 및 for 루프를 사용하여 벡터 반복

vector<int> vec = {1,2,3,4,5}

for(auto itr : vec)
    cout << itr << " ";

산출:

1 2 3 4 5

이 방법을 사용하여 세트와 목록을 반복 할 수도 있습니다. 사용 자동차는 자동으로 템플릿에 사용 된 데이터 유형을 감지하고 당신이 그것을 사용할 수 있습니다. 그래서, 우리가했다 경우에도 vectorstring또는 char같은 구문은 잘 작동합니다


1

루프를 반복하고 값을 인쇄하는 올바른 방법은 다음과 같습니다.

#include<vector>

//declare the vector of type int
vector<int> v;

//insert the 5 element in the vector
for ( unsigned int i = 0; i < 5; i++){
    v.push_back(i);
}

//print those element
for (auto it = 0; it < v.end(); i++){
    std::cout << *it << std::endl;
}

1

다음은 벡터에서 값을 반복하고 인쇄하는 간단한 방법입니다.

for(int x: A) // for integer x in vector A
    cout<< x <<" "; 

0
 //different declaration type
    vector<int>v;  
    vector<int>v2(5,30); //size is 5 and fill up with 30
    vector<int>v3={10,20,30};
    
    //From C++11 and onwards
    for(auto itr:v2)
        cout<<"\n"<<itr;
     
     //(pre c++11)   
    for(auto itr=v3.begin(); itr !=v3.end(); itr++)
        cout<<"\n"<<*itr;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.