← SEARCHABLE ARCHIVE
C / C++ · 2026-08-12

C++ 기초부터 마스터까지 — 18화

Ranges와 Views로 지연 데이터 파이프라인 만들기

INTERACTIVE READING MODE →

본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.

반복자와 알고리즘은 컨테이너와 작업을 분리하지만 시작과 끝을 매번 따로 전달해야 했다. C++20 Ranges는 범위 자체를 받고, Views는 데이터를 복사하지 않는 지연 변환을 조합한다.

범위를 직접 알고리즘에 전달한다

#include <algorithm>
#include <vector>

std::vector<int> scores{30, 80, 50, 100};
std::ranges::sort(scores);

auto found = std::ranges::find(scores, 80);
if (found != scores.end())
{
    // 값을 찾았다.
}

begin과 end를 별도로 적지 않아도 되어 서로 다른 컨테이너의 반복자를 실수로 섞을 가능성이 줄어든다. projection을 사용하면 원소를 직접 변환하는 람다 없이 멤버 기준으로 정렬할 수도 있다.

std::ranges::sort(players, {}, &Player::Score);

View는 필요할 때 값을 계산한다

#include <ranges>

auto visibleNames = players
    | std::views::filter([](const Player& player)
      {
          return player.IsVisible;
      })
    | std::views::transform([](const Player& player) -> const std::string&
      {
          return player.Name;
      })
    | std::views::take(10);

for (const std::string& name : visibleNames)
{
    DrawName(name);
}

파이프라인을 만들 때 새 벡터 세 개가 생성되는 것이 아니다. 반복하면서 원소를 요청할 때 filter와 transform이 실행되고, take(10)은 최대 열 개에서 멈춘다.

View는 대부분 데이터를 소유하지 않는다

auto MakeBadView()
{
    std::vector<int> local{1, 2, 3};
    return local | std::views::filter([](int value) { return value > 1; });
}

위 View는 지역 벡터를 참조하지만 함수가 끝나면 벡터가 파괴된다. 반환된 View를 순회하면 이미 수명이 끝난 데이터에 접근한다.

View를 멤버에 저장하거나 함수 밖으로 반환할 때는 원본 범위가 얼마나 오래 사는지 확인해야 한다. 결과를 독립적으로 소유해야 한다면 명시적으로 컨테이너에 수집한다.

지연 평가는 오류 시점도 늦춘다

View를 생성하는 줄이 아니라 실제 반복하는 위치에서 변환 코드가 실행된다. 원본 컨테이너를 변경하면 반복자 무효화 규칙도 그대로 적용된다.

Ranges는 짧은 코드를 만드는 기능보다 데이터 흐름의 단계를 이름 있는 조합으로 표현하는 도구다. 파이프라인이 너무 길거나 상태 변경이 섞이면 중간 결과에 이름을 붙이고 일반 알고리즘이나 반복문으로 분리하는 편이 낫다.