[BOJ/C++] cin.tie(NULL)과 ios_base::sync_with_stdio(false) 그리고 endl...

gogori6565·2022년 7월 17일
2

백준 문제 15552번의 가장 큰 핵심포인트!
cin.tie(NULL)ios_base::sync_with_stdio(false) 그리고 endl에 대해 알아보자

문제를 풀기에 앞서 문제 내용에 이런 문장이 있다.

"C++을 사용하고 있고 cin/cout을 사용하고자 한다면, cin.tie(NULL)과 sync_with_stdio(false)를 둘 다 적용해 주고, endl 대신 개행문자(\n)를 쓰자. 단, 이렇게 하면 더 이상 scanf/printf/puts/getchar/putchar 등 C의 입출력 방식을 사용하면 안 된다."

시간을 줄이기 위한 키포인트 같은데..
뭔지는 알고 적용해야 할 것 같아서 알아보았다.

👉 cin.tie(NULL)ios_base::sync_with_stdio(false) 은 대게 main의 첫번째 줄에 작성한다.


ios_base::sync_with_stdio(false)

💡 ios_base::sync_with_stdio(false) : C의 stdio와 C++의 iostream의 동기화를 비활성화 한다 (즉, 평소엔 서로 동기화 상태)

기본적으로 C++와 C의 표준 스트림은 동기화되어있다. 즉, C++에서 C와 C++ 각각의 스타일로 입출력을 받아도 서로 동기화해 우리가 입력/출력하고자 하는 순서대로 결과를 얻을 수 있다. C와 C++가 동일한 버퍼를 공유한다는 것이다.

  • 단, 이 경우 iostream과 stdio의 버퍼를 모두 사용하여 딜레이가 발생한다(성능저하)
    대신, 두 스트림이 동기화하여 입출력에 있어 C와 C++의 IO(Input/Output)을 혼용해 쓸 경우 합리적이고, 스레드(thread)로부터 안전하다.

ios_base::sync_with_stdio(false)을 통해 동기화를 끊으면 C++ 표준 스트림이 독립적으로 IO 버퍼링을 하게 되어 많은 양의 입출력이 있을 경우 성능이 많이 좋아진다.

  • 알고리즘 문제 풀이에서는 예외 처리나 멀티스레드 작업이 필요하지 않기에 두 동기화를 끊고 성능을 높여 시간을 줄이는 게 더 효율적이다.

🛑 주의사항!

  • 동기화가 비활성화된 경우,
    버퍼가 분리되었기 때문에 cin과 C의 scanf, gets, getchar 등을 같이 사용하면 안되고,
    cout와 C의 printf, puts, putchar 등과 같이 사용하면 안된다.

cin.tie(NULL)

💡 cin.tie(NULL) : 입력과 출력 연결을 끊어준다 (cin.tie(nullptr) 또는 cin.tie(0) 도 가능)

원래 coutcin, 입출력은 묶여있다.
입력요청이 들어오면 그 전에 출력 작업이 있었을 경우(출력 버퍼에 내용이 있는 경우) 버퍼를 비워(flush) 출력하게 된다.

  • 이 경우, 입출력이 반복될 때, 일일이 버퍼를 지우느라 시간이 오래 걸린다. 따라서, cin.tie(NULL) 을 통해 입출력 묶음을 풀면 시간이 단축된다.

🛑 주의사항!

입출력 순서를 보장받을 수 없다.

예를 들어 좀 더 자세히 설명해보겠다.

[입출력이 묶여있는 경우]

#include<iostream>
using namespace std;

int main(void){
	ios_base::sync_with_stdio(false);

    int t,num1,num2;
    cin>>t;

    for(int i=0;i<t;i++){
        cin>>num1>>num2;
        cout<<num1+num2<<"\n";
    }
}

이때, 입력과 출력은 순서대로 이루어진다.
입력 한 번에 출력이 매번 이루어지는 것이다.

2     //test case
1 1   //입력
2     //출력
2 2   //입력
4     //출력

[입출력 묶음이 풀려있는 경우]

#include<iostream>
using namespace std;

int main(void){
	cin.tie(NULL); //입출력 묶음 해제
    ios_base::sync_with_stdio(false);

    int t,num1,num2;
    cin>>t;

    for(int i=0;i<t;i++){
        cin>>num1>>num2;
        cout<<num1+num2<<"\n";
    }
}

이 경우, 입출력이 순서대로 출력되지 않는 걸 볼 수 있다.

2	  //test case
1 1   //입력
2 2   //입력
2     //출력
4	  //출력

입력을 한 번에 받고, 출력이 나중에 한 번에 처리된다.
즉, 매번 출력을 비우지(flush)않고 나중에 한 번에 비우도록 하는 것이다.


endl 대신 "\n"

endl 은 개행 뿐만아니라 출력 버퍼를 비우는(flush) 역할도 한다.

  • 이 출력 버퍼를 비우는 작업도 상당히 시간을 잡아먹기에 마지막 한 번에 출력을 비우는 것이 좋다. (물론, 버퍼가 꽉차면 알아서 비워준다)

+) endl은 출력 버퍼를 비우기 때문에 위에서 다룬 cin.tie(NULL)의 역할인 묶음을 끊어주는 효과를 볼 수 없게 한다.

["\n"대신 endl을 사용할 경우]

#include<iostream>
using namespace std;

int main(void){
    cin.tie(NULL); ios_base::sync_with_stdio(false);

    int t,num1,num2;
    cin>>t;

    for(int i=0;i<t;i++){
        cin>>num1>>num2;
        cout<<num1+num2<<endl;
    }
}

분명 cin.tie(NULL) 을 작성했음에도 endl 이 출력 버퍼를 비워 입력과 출력이 순서대로 이루어지는 결과를 볼 수 있다.

2     //test case
1 1   //입력
2     //출력
2 2   //입력
4     //출력

15552번 문제 제출하면서 cin.tie(NULL)ios_base::sync_with_stdio(false)를 뺀 경우와, endl 을 적용시킨 두 경우 모두 제출해보았는데 둘 다 시간초과 가 떴다!

문제 출처 : https://www.acmicpc.net/problem/15552

profile
p(´∇`)q

0개의 댓글