https://www.acmicpc.net/problem/15552
백준 15552번, 빠른 A+B를 통해서 C++의 빠른 입출력 팁을 알아내보자.
참고한 링크는 다음과 같다.
https://st-lab.tistory.com/232
먼저 정답 코드는 다음과 같다.
#include <iostream>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int T, a, b;
cin >> T;
for (int i = 0; i < T; i++) {
cin >> a >> b;
cout << a + b << "\n";
}
}
C++에서 표준으로 사용하는 입출력인 cin과 cout의 경우, C언어에서 사용하던(그리고 C++에서도 그대로 호환되는) scanf()와 printf()에 비해서 실행 속도가 꽤 느리다. 이는 cin과 cout이 뒤 2개보다 더 많은 기능을 내포하고 있기 때문이다.
이를 완화시키고, cin과 cout을 사용하면서도 처리 속도를 빠르게 하는 방법 3가지를 알아보겠다.
기본적으로, C++의 cin과 cout은 C 표준 라이브러리의 입출력 함수(scanf, printf 등)와의 호환성 및 동기화를 보장하기 위해서, 입출력 스트림을 동기화 하는 매커니즘을 사용하고 있다. 이 덕분에 printf, scanf, cin, cout을 혼용해서 사용하더라도 버퍼링 문제를 방지하고, 일관된 결과를 얻을 수 있다. 하지만, 이로 인해서 추가적인 오버헤드(overhead)가 발생해서 실행 속도가 느려지게 된다.
다만, 백준 등 알고리즘 문제를 풀 경우에는 이러한 예외 처리나 멀티 스레딩 작업이 필요하지 않기 때문에, 동기화를 끊어주어도 무방하다.
동기화를 끊게 되면 C++ 표준 스트림이 독립적으로 입출력 버퍼링 수행이 가능하다. 또한 성능이 상당히 많이 올라가게 된다.
동기화를 끊어주기 위해선, 다음과 같은 코드를 사용하면 된다.
ios_base::sync_with_stdio(false);
stdio.h와의 동기화(sync)를 끊는다는 느낌이 바로 오는 작명이다. 이걸 하게 된다면 C 스타일 혹은 C++ 스타일 둘 중 하나만 써야하며, 동시에 사용하면 안된다.
입력과 출력은 기본적으로 연결이 되어있다.
입력이 들어왔을 때 그 전에 출력 작업을 수행 중이었던 경우, 출력 버퍼를 비워내어(flush) 출력을 하게 된다. 입력 요청을 통해 데이터를 읽어들이게 될 경우, 이 전에 있던 출력 작업들을 콘솔창에 보이도록 버퍼를 비운다는 뜻이다.
백준의 경우, 입력과 출력을 분리하고 있기 때문에 굳이 입력과 출력을 번갈아 가면서 연결시켜놓고 사용할 필요가 없다. 출력문만 채점 파일과 동일하면 무방하기 때문에, 매번 출력을 하지 않고, 나중에 한번에 시키도록 하면 된다.
이는 다음 코드로 구현이 가능하다.
cin.tie(NULL);
C++ 이론에 대해서 공부하는 포스팅을 보면
https://velog.io/@hy_k/C-C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8%EC%9D%98-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%EA%B5%AC%EC%84%B1%EA%B3%BC-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%B2%98%EB%A6%AC
알겠지만은, \n과 endl 사이에는 차이가 있다. endl는 즉시 출력 버퍼에 있는 데이터를 비우라고 지시함으로, tie를 끊어도 endl를 사용하면 계속 출력이 이뤄진다. 따라서 endl 대신에 \n을 사용하는 것이 tie와 함께 사용했을 때 효과가 좋다.