C, C++/C++ 언어 / / 2024. 5. 14.

[C++] 범위 기반 for 루프 (Range-based for loop) 사용법

범위 기반 for

범위 기반 for 루프는 배열이나 컨테이너 같이 데이터의 연속을 나타내는 객체의 모든 멤버를 순환하는 구문입니다.

이 기능은 C++11부터 도입되었습니다.

 

선언 방식은 다음과 같습니다.

for ( 데이터_타입 변수명 : 배열 or 컨테이너 등 순환가능한 객체 ){}

범위 기반 for 구문의 대상은 배열이나 컨테이너뿐 아니라, 데이터가 연속되어 있는 순환가능한 객체라면 대상이 될 수 있습니다.

예를 들어, 문자열 안에 있는 모든 문자를 출력하는데도 이 구문을 사용할 수 있습니다.

그리고, "데이터_타입"은 순환가능한 객체가 가진 멤버의 데이터 타입을 말합니다.

 

이 구문의 장점은 기존의 for 구문보다 알아보기 쉽고 짧은 코드를 만들 수 있다는 점입니다.

하지만 기존의 for 구문은 iterator를 통한 배열이나 컨테이너의 개별적인 멤버에 접근이 가능했지만, 범위 기반 for 구문은 멤버에 선택적인 접근을 할 수는 없습니다.

int main(){

    int arr[10] = {1,2,3,4,5,6,7,8,9,10};

    for(int i = 0; i < 9; i++){
        
        int sum = arr[i] + arr[i+1];	// 인덱스로 배열의 멤버에 접근
        cout << sum << " ";
    }
    
    cout << endl;
    
    for( int v : arr){
        cout << v << " ";	// 멤버의 값에 바로 접근
    }
    
    return 0;
}

예를 들면, 배열의 경우 인덱스를 통해 개별의 멤버의 값에 접근할 수 있습니다.

그러나, 범위 기반 for 구문에선 바로 객체에 접근하는 방식을 사용합니다.

 

구체적인 코드를 보면 사용법을 쉽게 알 수 있습니다.

배열의 모든 멤버를 출력하는 코드를 다음과 같이 바꿀 수 있습니다.

#include <iostream>
using namespace std;

int main(){

    int arr[10] = {1,2,3,4,5,6,7,8,9,10};

    for(int i = 0; i < 10; i++){	// 기존의 for 루프
        cout << arr[i] << " ";
    }

    cout << "\n";

    for(int v : arr){			// 범위 기반 for 루프
        cout << v << " ";
    }

    return 0;
}

 

std::vector의 모든 멤버를 출력하는 코드는 다음과 같이 변경할 수 있습니다.

int main(){

    vector<int> vec = {1,2,3,4,5,6,7,8,9,10};;

    // 기존의 for 루프
    for(vector<int>::iterator it = vec.begin(); it != vec.end(); it++){
        cout << *it << " ";
    }

    cout << "\n";

    for(int v : vec){		// 범위 기반 for 루프
        cout << v << " ";
    }

    return 0;
}

 

문자열의 모든 문자를 출력하기 위해서 사용할 수도 있습니다.

#include <iostream>
#include <string>
using namespace std;

int main(){

    string str = "This is a string";
    for(char c : str){
        cout << c << " ";
    }
    
    return 0;
}

 

범위 기반 for의 데이터 타입

범위 기반 for 구문의 데이터 타입은 참조(reference)const 키워드를 사용할 수 있습니다.

 

아래 예문은 클래스를 멤버로 가지고 있는 배열을 순환하는 코드입니다.

class CMyPoint{
public:
    int x, y;

    CMyPoint() : x(0), y(0) {};
};

int main(){

    CMyPoint ptArr[10];

    for(CMyPoint pt : ptArr){	// 범위 기반 for
    
        cout << pt.x << " , " << pt.y << "\n";
    }

    return 0;
}

여기서, 위와 같이 데이터 타입을 CMyPoint로 하면 함수가 인자로 값을 전달하는 것과 같이 pt 변수는 ptArr의 멤버를 복사하게 됩니다.

이때, 데이터가 복사되는 것을 막기 위해서 참조 테이터 타입을 사용할 수 있습니다.

for(CMyPoint& pt : ptArr){	// 참조 데이터 타입
    cout << pt.x << " , " << pt.y << "\n";
}

 

그리고, 참조 데이터 타입의 변수는 참조하고 있는 데이터의 값을 변경할 수 있습니다.

이러한 원본의 데이터 변경을 막기 위해서 const 키워드를 사용할 수 있습니다.

for(const CMyPoint& pt : ptArr){	// const 참조 데이터 타입
    cout << pt.x << " , " << pt.y << "\n";
    
    pt.x = 10;	// error !!
}

 

또한, auto 키워드도 사용할 수 있습니다.

auto 컴파일러가 선언된 변수 또는 변수의 초기화 식을 사용하여 해당 형식을 추론하도록 지시하는 키워드입니다.

for(const auto& pt : ptArr){	// const auto 데이터 타입
    cout << pt.x << " , " << pt.y << "\n";
}

위의 auto 키워드는 CMyPoint 타입으로 처리됩니다.

 

범위 기반 for 구문으로 std::map 데이터 순환

map 컨테이너의 데이터를 순환하기 위해 범위 기반 for 구문을 사용하면 다음과 같습니다.

#include <iostream>
#include <map>
using namespace std;

int main(){

    map<int, int> myMap{ {1,2}, {2,2}, {3,4} };

    for( pair<const int, int>& i : myMap){
        cout << i.first << " " << i.second << "\n";	// first, second를 사용
    }
}

 

C++17 버전 이후에는, 위의 구문을 아래와 같이 변경할 수 있습니다.

int main(){

    map<int, int> myMap{ {1,2}, {2,2}, {3,4} };

    for( auto& [key, value] : myMap){
        cout << key << " " << value << "\n";	// key, value 사용
    }
 
    return 0;
}

pair의 first, second 대신 key와 value 이름으로 직접 데이터에 접근할 수 있습니다.

 

 

이 글과 관련 있는 글들

범위 기반 for를 사용하기 위한 사용자 타입의 필요조건

 

 

 

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유