cin / cout 을 사용하고자 한다면
sync_with_stdio(false);
cin.tie(NULL);
를 둘 다 적용하라고 한다.
그리고 endl 대신 개행문자를 써야한다.
문제의 요지는 '시간을 최대한 줄여라.' 이다.
#include <iostream>
using namespace std;
int main()
{
cin.tie(NULL);
ios::sync_with_stdio(false);
int T;
cin >> T;
int a, b = 0;
int *result = new int[T];
for (int i = 0; i < T; i++)
{
cin >> a >> b;
result[i] = a + b;
}
for (int i = 0; i < T; i++) { cout << result[i] << '\n'; }
}
조건에 명시된 저 두 줄을 추가해주고 개행문자를 썼다면
어려울 게 없는 문제였다.
근데 저 두 줄은 뭘 의미하는 걸까.
sync_with_stdio(false);
cin.tie(NULL);
먼저 알아야할건, 두 줄의 궁극적 기능은 단순 시간 단축이 아니다.
시간 단축은 side effect일 뿐이랜다.
이 두 줄을 추가하면 무조건 최적화를 도와준다! 이게 아니란 뜻.
ios_base::sync_with_stdio(false);
sync_with_stdio는 C와 C++의 standard stream 간의 동기화를 시켜준다.
C를 배우고 C++로 넘어와서 첫 과제를 받았을 때에는,
cin과 cout이 익숙하지 않은 상태였기에 습관적으로 scanf, printf를 썼다.
근데 #include <iostream>만 추가하고, #include <stdio.h>는 안 했는데도
에러가 나지 않고 잘만 입출력이 되었다.
이를 통해 sync_with_stdio를 굳이 명시하지 않아도 동기화가 된다는 것을 알 수 있다.
둘을 섞어 써도 알아서 컴파일이 되고 실행이 된다니, 아주 편리하다.
그리고 동기화된 C++ stream들은 thread-safe 가 보장된다.
즉, 여러 thread가 동시에 사용되어도 안전하다는 것이다.
여기서 안전하다는 것은, 서로 다른 thread들이 같은 메모리에 동시에 접근하거나,
thread 하나가 동기화가 안 된다는 등의 불상사(data race)가 생기지 않는다는 뜻이다.
하지만, stdio 와 iostream 버퍼 두 개 다 쓰려니 delay가 생길 수 밖에 없다.
반면, sync_with_stdio(false) 는 그 동기화를 중지시키는 역할을 하고,
C++만의 독립적인 버퍼를 만들어낸다.
따라서, 이 상태에서 C를 섞어쓰면... 혼란스러울거다.
cout << "Hello";
printf("World");
cout << "Ciao";
왜 혼란스러울까?
동기화 없이 위의 코드를 돌리면,
HelloCiaoWorld / HelloWorldCiao / CiaoHelloWorld ...
이 중에서 뭐가 나올지 모르게 된다.
대신 버퍼 갯수를 줄이니 돌아가는 속도가 빨라지게 된다.
cin.tie(NULL);
cin 과 cout 은 기본적으로 묶여서(tie) 작동한다.
(우리가 평소에 쓰는 코드는 tied된 상태)
묶여서 작동함이란, cin 과 cout 이 같이 있을 때,
사용자로부터 입력값을 받기 전에 cout 버퍼가 먼저 비워짐(flush)을 말한다.
cout << "What's your name?";
cin >> name;
cin.tie(NULL); 은 이 묶음을 풀어준다(untie).
분리되면 cin 입력 전에 cout 버퍼를 무조건적으로 비우는 것을 멈추게 된다.
명령을 줘야만 버퍼를 비우게 된다.
예를 들어, 위의 코드를 untied 된 상태에서 돌린다면
What's your name? 이 출력되지 않은 상태에서 name 입력을 받게 된다.
왜냐하면 untied 된 cout(default 상태)은 따로 명령을 받거나,
버퍼가 가득 차야지만 버퍼를 비우고 출력을 하기 때문이다.
만약 끝에 endl을 붙여준다면, untied 된 상태지만
마치 tied 된 것처럼 실행될 것이다. (문장이 출력된 뒤 입력을 받을 것)
endl은 stream에 새로운 line을 추가해줌과 동시에 flush를 해주기 때문이다.
결론적으로, cin 과 cout 을 분리시킴으로써,
버퍼를 cout 할 때마다 비우는 과정을 생략할 수 있기에
속도가 빨라지는 효과를 볼 수 있는 것 같다.
'Training > BOJ' 카테고리의 다른 글
[C++] 11720 숫자의 합 (0) | 2020.07.20 |
---|---|
[C++] 2439 별 찍기 - 2 (0) | 2020.07.20 |
[C++] 2741 N 찍기 (0) | 2020.07.18 |
[C++] 2839 설탕 배달 (0) | 2020.07.18 |
[C++] 1008번 A/B (2) | 2020.07.18 |