1 minute read

스트림과 반복자(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_iteratorstd::cin의 iterator를 생성해야한다. std::istream_iterator의 기본 생성자는 end-of-stream이다. 스트림의 끝을 나타내는 것이다.

1-2 std::istream_iteratorstd::cinend-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_iteratorauto와 비슷하게 대응되는 인스턴스의 클래스에 맞게 변화한다.(자세한 내용은 여기)

결국 std::copy(cin_iter, eos, std::back_inserter(num));std::cin의 iterator부터 end-of-stream iterator까지를 입력으로 numback_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;
}

결과

Categories:

Updated:

Leave a comment