콘텐츠로 이동

스트림 (Streams)

적절한 곳에 스트림을 사용하되 "단순한" 사용법을 고수하세요. <<는 값을 표현하는 타입에 대해서만 스트리밍 연산자로 오버로드하고, 구현 세부사항이 아니라 사용자에게 보이는 값만 출력하세요.

정의:

스트림은 표준 헤더 <iostream>으로 대표되는 C++의 표준 I/O 추상화입니다. Google 코드에서 널리 쓰이며, 대부분 디버그 로깅과 테스트 진단 용도입니다.

장점:

<<와 >> 스트림 연산자는 배우기 쉽고 이식 가능하며 재사용과 확장이 가능한 형식화 I/O API를 제공합니다. 이에 비해 printf는 사용자 정의 타입은 고사하고 std::string조차 지원하지 않으며, 이식성 있게 쓰기가 매우 어렵습니다. 게다가 printf는 조금씩 다른 수많은 버전 중에서 하나를 골라야 하고, 수십 가지 변환 지정자를 헤쳐 나가야 합니다.

스트림은 std::cin, std::cout, std::cerr, std::clog를 통해 콘솔 I/O를 일급으로 지원합니다. C API도 그렇긴 하지만, 입력을 직접 버퍼링해야 한다는 점이 발목을 잡습니다.

단점:

  • 스트림의 형식 지정은 스트림의 상태를 바꿔서 설정할 수 있습니다. 그런 변경은 계속 남아 있으므로, 다른 코드가 스트림을 건드렸을 만한 지점마다 일부러 알려진 상태로 되돌려 놓지 않는 한, 여러분 코드의 동작이 그 스트림의 과거 이력 전체에 영향을 받을 수 있습니다. 사용자 코드는 내장된 상태를 수정할 수 있을 뿐 아니라, 등록 시스템을 통해 새로운 상태 변수와 동작을 추가할 수도 있습니다.
  • 위의 문제들, 스트리밍 코드에서 코드와 데이터가 뒤섞이는 방식, 그리고 (기대와 다른 오버로드가 선택될 수 있는) 연산자 오버로딩 때문에 스트림 출력을 정밀하게 제어하기가 어렵습니다.
  • << 연산자를 사슬처럼 이어 출력을 만들어 가는 방식은 국제화를 방해합니다. 어순이 코드에 굳어져 버리는 데다, 스트림의 지역화 지원에는 결함이 있기 때문입니다.
  • 스트림 API는 미묘하고 복잡해서, 효과적으로 쓰려면 프로그래머가 경험을 쌓아야 합니다.
  • <<의 수많은 오버로드를 해결하는 일은 컴파일러에게 대단히 비쌉니다. 큰 코드베이스에서 광범위하게 쓰이면 파싱과 의미 분석 시간의 20%까지 잡아먹을 수 있습니다.

결정:

스트림은 그 일에 가장 알맞은 도구일 때만 쓰세요. 보통은 I/O가 임시적이고 지역적이며 사람이 읽을 수 있고, 최종 사용자가 아니라 다른 개발자를 대상으로 할 때가 그렇습니다. 주변 코드 및 코드베이스 전체와 일관되게 하세요. 그 문제에 이미 확립된 도구가 있다면 그 도구를 대신 쓰세요. 특히 진단 출력에는 대개 로깅 라이브러리가 std::cerr이나 std::clog보다 나은 선택이고, absl/strings나 그에 준하는 라이브러리가 대개 std::stringstream보다 나은 선택입니다.

외부 사용자를 마주하거나 신뢰할 수 없는 데이터를 다루는 I/O에는 스트림을 쓰지 마세요. 대신 국제화, 지역화, 보안 강화 같은 문제를 처리해 주는 적절한 템플릿 라이브러리를 찾아 쓰세요.

스트림을 쓴다면 (오류 상태를 제외한) imbue(), xalloc(), register_callback() 같은 스트림 API의 상태 보유 부분은 피하세요. 진법, 정밀도, 자리 채움 같은 형식 지정 세부사항을 제어할 때는 스트림 조작자나 형식 플래그 대신 absl::StreamFormat() 같은 명시적인 형식화 함수를 쓰세요.

<<를 여러분 타입의 스트리밍 연산자로 오버로드하는 것은 그 타입이 값을 표현하고, <<가 그 값의 사람이 읽을 수 있는 문자열 표현을 출력하는 경우에만 하세요. <<의 출력에 구현 세부사항이 드러나지 않게 하세요. 디버깅을 위해 객체 내부를 출력해야 한다면 이름 있는 함수를 대신 쓰세요(DebugString()이라는 이름의 메서드가 가장 흔한 관례입니다).


옮긴이 풀이

핵심: 적절할 때만, "간단하게" 쓰기

스트림(<iostream>)은 C++ 표준 I/O 추상화로, 주로 디버그 로깅·테스트 진단에 씁니다. 쓰더라도 단순한 사용에 머무르세요.

언제 쓰나 / 쓰지 않나

  • 써도 됨: I/O가 임시적·지역적이고 사람이 읽을 용도이며, 대상이 최종 사용자가 아닌 개발자일 때.
  • 쓰지 말 것: 외부 사용자 대상이거나 신뢰할 수 없는 데이터를 다루는 I/O. (국제화·보안을 처리하는 템플릿 라이브러리를 쓰세요.)
  • 이미 확립된 도구가 있으면 그것을 쓰세요. 진단 출력엔 std::cerr·std::clog보다 로깅 라이브러리를, 문자열 조립엔 std::stringstream보다 absl/strings를 쓰는 편이 낫습니다.

주의

  • imbue(), xalloc(), register_callback() 같은 상태 보유(stateful) API는 피하세요(오류 상태 제외). 형식 지정은 스트림 조작자 대신 명시적 함수(absl::StreamFormat() 등)로.
  • <<는 값을 나타내는 타입에만, 사람이 읽을 표현을 쓰도록 오버로드하세요. 구현 세부사항을 노출하지 마세요. 디버깅용 내부 출력은 DebugString() 같은 이름 있는 함수로.