C++ 범위 기반 for 문

Seongcheol Jeon·2024년 12월 7일
0

CPP

목록 보기
32/47
post-thumbnail

범위 기반 for 문 형식

범위 기반 for문은 개발자가 반복을 직접 제어하지 않고 대상 데이터 집합의 크기만큼만 순회하는 방법이다. 형식은 다음과 같다.

for (데이터_형식_변수_이름 : 배열_또는_컨테이너) { 반복_실행문 }

기존 for문은 개발자가 지정한 횟수를 반복해서 작업하고 이를 활용해 데이터에 접근하므로 어떤 데이터 형식이든지 순회할 수 있었다. 반면에 범위 기반 for문은 사용법이 단순한 대신 순회할 수 있는 데이터 형식이 제한된다. 컴파일러가 반복 횟수를 명확히 알 수 있는 데이터 형식만 사용할 수 있다.

범위 기반 for문에 사용할 수 있는 대표적인 데이터 형식은 배열이다. 정적인 크기의 배열은 char, int, float 등 배열 원소의 데이터 형식과 무관하게 사용할 수 있다. 단 포인터로 동적 할당한 메모리나 매개변수로 전달받은 배열은 범위 기반 for문에 사용할 수 없다.

배열 외에도 유니폼 초기화로 초기화된 리스트나 begin, end 함수를 제공하는 컨테이너를 사용할 수 있다. 유니폼 초기화로 초기화된 리스트는 컴파일러가 크기를 명확히 할 수 있으며 begin, end 함수를 제공하는 컨테이너 클래스들은 시작과 끝을 명확히 알 수 있다.

#include <iostream>
#include <array>

using std::cout;
using std::endl;


int main()
{
    std::array<int, 10> numbers{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    for (int i = 0; i < 10; i++) {
        cout << numbers[i] << endl;
    }

    cout << endl;

    for (const auto& num : numbers) {
        cout << num << endl;
    }

    return 0;
}

범위 기반 for문으로 순회할 수 있는 데이터 형식은 제한되므로 기존 for문을 완전히 대체할 수 없다. 또한 범위 기반 for문은 개발자가 반복을 직접 제어할 수 없으므로 제어 변수를 선언해 인덱스를 활용하거나 홀수/짝수 번째 원소에 접근하는 등의 작업을 반복문 안에서 직접 구현해 줘야 한다.

이런 제약 사항을 잘 기억하고 기존 for문과 범위 기반 for문을 상황에 맞게 사용해야 한다.

배열이나 리스트를 하나씩 모두 순회하는 경우가 아니라면, 기존 for문 형태로 사용하는 것이 좋다.

범위 기반 for문 활용

범위 기반 for문은 일반적으로 다음 4가지 형태로 사용된다.

  • 데이터 집합 원소 복사
    • for (auto 변수이름 : 배열또는_컨테이너) {}
      • 데이터 집합을 순회하면서 변수에 값이 차례로 복사된다. 이때 개별 원소를 저장할 변수를 auto 형식으로 선언하면 형식 연역을 통해서 데이터를 안전하게 복사할 수 있다. 다만, 데이터 집합의 원소를 변수에 복사하므로 추가 시간이 소요되며, 해당 변수는 복사본이어서 반복문 안에서 실제 원소값을 변경할 수 없다.
  • 데이터 집합 원소 참조
    • for (auto& 변수이름 : 배열또는_컨테이너) {}
      • 데이터 집합의 원소를 참조로 접근하는 방법이다. 참조 변수이므로 원소값을 변경할 수 있다.
  • 데이터 집합 원소 상수 참조
    • for (const auto& 변수이름 : 배열또는_컨테이너) {}
      • 위와 동일하지만 값 변경이 불가하다.
  • 데이터 집합 원소 Rvalue 참조
    • for (auto&& 변수이름 : 배열또는_컨테이너) {}
      • 원소값을 참조하지 않고 값으로 가져오지만, 복사가 이루어지지 않고 Rvalue 참조를 사용한다.

R-value 참조란 무엇일까?

R-value 참조C++11부터 추가된 모던 C++의 주요한 개념이다. 이것을 이해하려면 std::move 혹은 std::forward 함수를 공부해야 한다.

R-value는 임시로 만들어지거나 특정 범위에서만 존재하는 값이다. 따라서 R-value를 전달받아 사용하려면 반드시 사용하는 범위의 R-valueL-value가 가르키는 메모리 영역에 복사하는 과정이 필요하다.

매우 적은 리소스가 필요한 R-value라면 문제가 없지만, std::vectorstd::string처럼 리소스가 많이 필요한 R-value라면 복사 과정이 반복될 때 실행 성능이 떨어지게 된다.

이런 단점을 보안하고자 R-value를 복사하지 않고 사용하는 범위(함수나 클래스 등)로 이동할 수 있도록 한 것이다. 즉, 이름 없는 객체인 R-value는 선언 범위를 벗어나면 소멸하는데 다른 범위에서도 사용할 수 있도록 해당 범위의 R-value이동(move)하게 하는 방법이다.

범위 기반 for문의 auto&& 형태처럼 auto&&로 전달된 R-value 참조auto변수 사용법이 동일하지만, 전달 과정에서 복사가 이루어지지 않아 속도가 더 빠르다.

구현은 조금 더 복잡하지만 사용법은 간단하고 성능 면에서 이점이 많으니 잘 사용하면 도움이 된다.

R-value 참조를 사용하려면 컨테이너나 배열에서 R-value 참조가 가능하도록 지원해야 한다.

0개의 댓글