스트림(stream)(4) 반복문 없이 벡터 입/출력 (std::vector I/O without loop statement)
스트림과 반복자(iterator)를 활용하면 for/while문 없이 std::vector를 입/출력 할 수 있다. 최종 코드
1. std::istream_iterator
코드부터 보자면 다음과 같다
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::istream_iterator<int> cin_iter(std::cin);
std::istream_iterator<int> eos;
std::vector<int> num;
std::copy(cin_iter, eos, std::back_inserter(num));
for(auto it: num) {
std::cout << it << std::endl;
}
return 0;
}

1-1 <iterator> 내부에 정의된 std::istream_iterator
std::istream 클래스는 iterator를 자식으로 두고 있지 않다. 다른 STL 컨테이너 클래스처럼 std::cin.begin()으로 iterator를 만들 수 없다는 뜻이다.
그래서 std::istream, 위 코드에서는 std::cin의 iterator를 사용하기 위해서는 <iterator> 헤더를 include해야 하고, 헤더에 선언된 std::istream_iterator로 std::cin의 iterator를 생성해야한다. std::istream_iterator의 기본 생성자는 end-of-stream이다. 스트림의 끝을 나타내는 것이다.
1-2 std::istream_iterator와 std::cin의 end-of-stream 차이
std::cin의 >> 연산과 달리, std::istream_iterator는 스페이스나 엔터키로 스트림 입력을 끊지 않는다. 위 코드에서는 ^D(ctrl+D)로 EOF 플래그를 입력해 스트림의 끝을 알린다. 그래서 위 사진에 ^D가 다음 줄에 있는 것이다. EOF 또한 입력이므로 입력 내용이랑 구분(위 경우에서는 스페이스로 간격을 주고)해 입력해야한다.
1-3 std::copy
std::copy()는 <algorithm> 헤더에, 선언된 함수이다.
std::copy()는 3가지 parameter가 들어간다. 각각 입력 인스턴스의 시작 iterator와 끝 iterator, 출력 인스턴스의 시작 iterator이다.
std::vector<int> copy_src = {1, 3, 5};
std::vector<int> copy_dst;
std::copy(copy_src.begin(), copy_src.end(), copy_dst.begin());
// copy_dst에 1, 3, 5가 복사됨
1-4 std::back_inserter
std::back_inserter()는 <iterator> 헤더에 선언된 함수이다.
std::back_inserter()는 컨테이너(이 경우에서는 std::vector)를 argument로 가지고, std::back_insert_iterator를 return한다. std::back_insert_iterator는 auto와 비슷하게 대응되는 인스턴스의 클래스에 맞게 변화한다.(자세한 내용은 여기)
결국 std::copy(cin_iter, eos, std::back_inserter(num));은 std::cin의 iterator부터 end-of-stream iterator까지를 입력으로 num의 back_insert_iterator에 복사하는 동작이다.
2. std::ostream_iterator
위 내용을 이해했다면 std::ostream_iterator는 이해하기 쉽다.
#include <iostream>
#include <vector>
#include <iterator>
int main() {
std::vector<int> num = {1, 3, 5, 7};
std::ostream_iterator<int> cout_iter(std::cout);
std::copy(num.begin(), num.end(), cout_iter);
return 0;
}

여기서 std::istream_iterator가 구분자(delimiter)를 std::cin을 따라 스페이스바로 가져간 것처럼, std::ostream_iterator 또한 std::cout처럼 빈칸 없이 출력된다. 이때 다음과 같이 선언하면 구분자를 줄 수 있다.
std::ostream_iterator<int> cout_iter(std::cout, ", ")

3. 합쳐서
두 stream_iterator를 합치면 다음과 같은 코드가 나온다.
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> num;
std::istream_iterator<int> cin_iter(std::cin);
std::istream_iterator<int> eos;
std::ostream_iterator<int> cout_iter(std::cout, " ");
std::copy(cin_iter, eos, std::back_inserter(num));
std::copy(num.begin(), num.end(), cout_iter);
return 0;
}

Leave a comment