Training/BOJ

[C++] 15552 빠른 A+B

FATKITTY 2020. 7. 20. 02:12
반응형

 

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