// 예를 들어 int 타입의 최대 값을 구하고 싶다면 <limits> 헤더 파일을 포함시킨 후
// numeric_limits<int>::max() 처럼 사용하면 된다.
#include <iomanip>
#include <iostream>
#include <limits>
using namespace std;
template <typename T> void ShowRange(const char *typeName)
{
cout << setw(20) << right << typeName << " (" << sizeof(T) << ") = ";
cout << setw(15) << right << numeric_limits<T>::min() << " ~ ";
cout << setw(15) << left << numeric_limits<T>::max() << endl;
}
int main()
{
ShowRange<signed char>("signed char");
ShowRange<unsigned char>("unsigned char");
ShowRange<signed short>("signed short");
ShowRange<unsigned short>("unsigned short");
ShowRange<signed int>("signed int");
ShowRange<unsigned int>("unsigned int");
ShowRange<signed long>("signed long");
ShowRange<unsigned long>("unsigned long");
ShowRange<float>("float");
ShowRange<double>("double");
return 0;
}
iostream
헤더 파일을 보면 다음과 같이 cout
과 cin
객체를 선언하고 있다. extern
이 붙어 있는 것을 봐서는 실체 객체의 정의는 어딘가 구현 파일에 있을 것으로 예상할 수 있다.
extern ostream cout;
extern istream cin;
중요한 것은, ostream
과 istream
클래스 타입을 갖는다는 점인데, 사실 이들은 그냥 클래스가 아니라 템플릿 클래스
를 다음과 같이 재정의한 타입이다.
typedef basic_ostream<char> ostream;
typedef basic_istream<char> istream;
결국 cout
과 cin
객체의 실제 클래스는 basic_ostream
과 basic_istream
인 것이다. 클래스의 이름을 보면 기본적인(basic) 출력(output) 스트림(stream), 기본적인 입력(input) 스트림 정도로 해석이 되는데, 여기서 스트림(stream)
의 개념을 이해할 팔요가 있다.
stream
이란 시내, 개울, 흐름 등의 사전적인 의미가 있다. 그와 비슷하게 C++
에서의 stream
은 연결된 통로로 흘러가고 있는 데이터를 연상하면 된다.
위의 그림에서 볼 수 있듯이 스트림
의 왼쪽에서 데이터를 넣으면, 스트림
의 오른쪽에 있는 프로그램에서 데이터를 꺼내서 사용한다. 그것이 실제로 누구로부터 왔는지는 신경 쓰지 않아도 된다. 파일일 수도 있고, 콘솔일 수도 있고, 또 다른 프로그램일 수도 있다. 결국 스트림
의 양 끝에서 데이터를 주고 받는 객체가 서로에 대해서 모르는 상태에서도 데이터를 주고 받을 수 있다. 즉, 스트림
을 통해서 서로간의 연관성(Coupling)
이 없어지는 것이다.
제일 아래쪽에 basic_istream
과 basic_ostream
클래스가 있고, 이 두 클래스 모두 basic_ios
클래스를 상속 받고 있다. basic_ios
는 입출력 스트림 클래스들에서 공통적으로 사용하는 기본 기능을 구현하고 있다. 또한 스트림 내부적으로 사용하는 메모리를 관리하기 위한 basic_streambuf
클래스도 있다. 그리고 그 위에는 ios_base
라는 최상위 클래스가 있는데, 이 클래스는 출력을 예쁘게 만들 수 있는 여러 가지 옵션을 구현하고 있다.
출력 스트림을 사용해서 자료를 보낼 때, 자료가 파일이나 콘솔 창으로 그 즉시 출려괴는 것이 아니다. 우선은 받은 자료를 모아두었다가 적당한 양이 쌓이면, 한 번에 콘솔 창이나 파일로 출력하게 된다. 매번 보내는 것 보다 한 번에 모아서 보내는 것이 보다 효율적이기 때문인데, 특히 파일에 자료를 출력하는 경우에는 더욱 그렇다.
입력 스트림을 사용하는 경우에도 마찬가지로 파일이나 콘솔 창이나 한 번에 여러 바이트를 모아서 읽어 들인 후에 조금씩 주는 방식을 사용한다. 이렇게 데이터를 모았다가 보내는 작업을 버퍼링(Buffering)
이라고 부른다.
일반적으로 자료가 어느 한 곳에서 다른 곳으로 이동할 때, 잠시 보관되는 메모리를 버퍼
라고 부르고, 버퍼
를 사용해서 모았다가 한 번에 보내는 것을 버퍼링
이라고 부른다. C++
의 입출력에서만 사용하는 용어는 아니고 컴퓨팅 전반에 걸쳐서 사용하는 용어다.
그런데 가끔씩은 버퍼링
을 하지 않게 만들고 싶은 경우가 있다. 예를 들어 출력한 내용을 곧바로 다른 작업에 사용해야 한다면 될 수 있는 한 빨리 출력할 필요가 있다. 이럴 때는 버퍼
에 있는 내용을 지금 당장 방출(Flushing)
하라는 명령을 내릴 수가 있는데, 다음과 같은 두 가지 방법을 사용할 수 있다.
cout << "Hello World! << endl << flush;
cout << "Hello World! << endl;
두 줄의 코드는 동일한 일을 하고 있는데, 첫번째 줄은 Hello World!
라는 문자열을 버퍼
로 보낸 후에 버퍼
의 내용을 그 작시 출력하게 만든다. 두 번째 줄에서 쓰인 endl
은 개행 문자를 출력한 후에 버퍼
의 내용을 방출
하게 만든다.
일반적으로 방출
명령을 사용할 일은 거의 없다. 그 대신 내부적으로 버퍼링
을 수행한다는 사실을 꼭 기억하고 있어야 한다. 혹시라도 출력한 문자가 바로 출력되지 않는 문제를 만나게 되면 버퍼링
을 의심해 볼수 있어야 한다.
입출력 형식을 지정한다는 것은 한 마디로 출력을 예쁘게 꾸미는 것을 말한다. 출력하는 값을 한 쪽으로 정렬한다던가 16진수로 출력하게 만든다거나, 소주점 이하 자릿 수를 제한하는 등의 작업을 말하는 것이다.
입출력 형식을 지정하는 가장 기본적인 방법은 iso_base
클래스의 setf()
함수를 사용하는 것이다. setf()
함수는 다음과 같이 오버로드된 두 가지 버전이 있다.
fmtflags setf(fmtflags f);
fmtflags setf(fmtflags f, fmtflags mask);
예를 들어 bool
값을 0
, 1
이 아닌 true
, false
의 형태로 출력하고 싶다면 다음과 같이 하면 된다.
cout.setf(ios_base::boolalpha);
cout << true << endl; // 1이 아닌 true가 출력된다.
setf()
함수의 인자로 넣을 수 있는 값들은 다음에 나오는 표에 정리해두었다. 이 값들은 iso_base
클래스안에서 정의하고 있기 때문에 iso_base::boolalpha
처럼 영역을 지정해서 사용해야 한다.
구분 | 값 | 의미 |
---|---|---|
인자가 하나인 setf() 함수에 사용할 수 있는 값 | showbase | 진법을 나타내는 기호(0x, O)를 함께 출력한다. 예를 들어 16진수는 0x1F 처럼 출력한다. |
showpoint | 실수를 출력할 때 항상 소수점을 출력한다. | |
showpos | 양수의 경우에도 + 기호를 붙여서 출력한다. | |
uppercase | 실수를 scientic으로 출력할 때 사용하는 문자 'E'나 정수를 16진수로 출력할 때 사용하는 영문자들을 대문자로 출력한다. | |
boolalpha | bool 타입의 값을 1, 0이 아닌 true, false의 형태로 출력하거나 입력받는다. | |
인자가 두 개인 setf() 함수의 첫번째 인자로 사용할 수 있는 값 | dec | 정수를 10진수로 출력하거나 입력받는다. |
hex | 정수를 16진수로 출력하거나 입력받는다. | |
oct | 정수를 8진수로 출력하거나 입력받는다. | |
internal | 값을 오른쪽으로 정렬해서 출력한다. 하지만 부호(+, -) 혹은 진법을 나타내는 기호(0x, O)는 왼쪽으로 정렬해서 출력한다. | |
left | 값을 왼쪽으로 정렬해서 출력한다. | |
right | 값을 오른쪽으로 정렬해서 출력한다. | |
fixed | 실수를 항상 123.45와 같은 방식으로 출력한다. fixed로 지정하지 않은 경우에도 123.45와 같이 출력하지만 실수의 값이 너무 작거나 너무 큰 경우에는 1.23E+006와 같이 출력할 수도 있다. 하지만 fixed로 지정하면 항상 123.45처럼 출력한다. | |
scientific | 실수를 항상 1.23E+006 처럼 출력한다. | |
인자가 두 개인 setf() 함수의 두번째 인자로 사용할 수 있는 값 | adjustfield | (internal | left | right)와 같은 값이다. internal과 left와 right를 비트 단위 OR 연산한 것이다. |
basefield | (dec | hex |oct)와 같은 값이다. | |
floatfield | (fixed | scientific)과 같은 값이다. |
위의 표는 크게 세 부분으로 나뉘어졌다.
cout.setf(ios_base::showpoint | iso_base::showpos)
처럼 비트 단위 OR
연산을 사용할 수 있는 것은 각 옵션 값들이 고유한 비트 값을 가지고 있기 때문이다. 다음과 같이 각 옵션 값들이 서로 다른 한 비트만 1의 값을 갖게 지정하는 것이다. 예를 들어 다음과 같이 값을 설정하고 있다고 하자. (2)
는 2진수
를 의미하고, (10)
은 10진수
를 의미한다.
showpoint = (2) 0000 0001 = (10) 1
showpos = (2) 0000 0010 = (10) 2
uppercase = (2) 0000 0100 = (10) 4
showpoint
는 첫 번째 비트만 1이고, showpos
는 두 번째 비트만 1이다. 이런 식으로 값을 배정하면 나머지 옵션 값들도 8, 16, 32와 같이 특정 비트 하나만 1로 셋팅된 값을 갖게 될 것이다. 이렇게 정해져 있다고 가정했을 때, showpoint | showpos
는 3의 값을 갖는다.
showpoint | showpos = (2) 00000001 | (2) 00000010 = (2) 00000011 = (10) 3
결국은 setf()
함수에 정수 3을 전달하는 것이다. 함수에 전달하는 인자는 단순한 정수 값 하나지만, 함수안에서는 비트를 분석함으로써 어떤 값들이 전달됐는지 확인할 수 있다. 예를 들어 인자로 전달한 값에 showpoint
를 포함했는지 확인하기 위해 다음과 같이 할 수 있다.
fmtflags setf(fmtflags f) {
if((f & showpoint) != 0)
// showpoint 값을 포함하고 있다.
}
여기서 f & showpoint
는 다음과 같은 의미를 갖는다.
f & showpoint = (2) 00000011 & (2) 00000001 = (2) 00000001 = (10) 1
매개 변수 f
안에서 showpoint
에 해당하는 비트가 1
로 셋팅된 경우에만 이 연산의 결과가 0
이 아닌 값을 가질 수 있으므로, 이 식을 통해서 매개 변수에 showpoint
가 포함되어 있는지 확인할 수 있다. showpoint
뿐만 아니라 다른 모든 옵션 값들에 대해서도 이런 방식을 사용해서 인자로 검사할 수 있다.
이 방법은 오래 전부터 널리 사용하는 방법으로 현재까지도 많은 곳에서 사용하고 있다. 하나의 정수 값 안에서 여러 가지 다양한 옵션 값들을 실어서 넘겨줄 수 있기 때문이다.
cout.setf(ios_base::hex, ios_base::basefield);
cout << 123 << endl; // 7B를 출력
setf()
함수는 두 가지 버전이 있다. 두번째 그룹에 속한 옵션들은 첫번째 그룹에 속한 것들과는 성격이 조금 다르다. 두 번째 드룹에 속한 옵션들은 동시에 사용할 수 없는 것들이 존재한다. 예를 들어 dec
, hex
, oct
는 동시에 사용할 수 없다. 정수를 10진수
이면서 16진수
이면서 8진수
로 출력할 수 없기 때문이다.
셋 중에 하나를 고르는 수 밖에 없다. internal
, left
, right
도 같은 관계에 있고, fixed
, scientific
도 같은 관계에 있다. 그렇기 때문에 이 옵션들은 단순히 켰다 껐다 하는 것이 아니라, 셋이나 둘 중에 하나를 고르는 방식을 사용해야 한다. 그리고 그것이 바로 두 가지 버전의 setf()
함수가 갖는 차이점이다.
만약 다음과 같이 잘못된 버전의 setf()
함수를 사용하면 원하는 대로 동작하지 않으니 주의해야 한다.
cout.setf(ios_base::hex);
cout << 123 << endl; // 16진수로 출력하지 않는다.
표에서 첫번째 그룹에 속한 값들은 인자를 하나 받는 setf()
를 사용하면 된다고 했는데, 이때는 여러 개의 값을 동시에 지정하는 것도 가능하다. 예를 들어 showpoint
, showpos
를 동시에 적용하고 싶다면 setf()
함수를 두 번 호출하는 대신 다음과 같이 호출할 수 있다.
cout.setf(ios_base:showpoint | iso_base::showpos);
cout << 123.0 << endl; // +123.000을 출력
이번에는 setf()
함수를 사용해서 지정한 옵션을 다시 취소하는 방법을 알아보자. 어떤 setf()
함수를 사용했느냐에 따라 달라지는데, 인자가 두 개 있는 setf()
함수를 사용한 경우라면 setf()
함수의 반환 값을 보관해두었다가 다시 되돌리는 방법을 사용한다.
// setf()의 반환 값을 보관
ios_base::fmtflags old_flags;
old_flags = cout.setf(ios_base::scientific, ios_base::floatfield);
cout << 12.34 << endl; // 1.234000e+001을 출력
// 보관한 값으로 다시 셋팅
cout.setf(old_flags, ios_base::floatfield);
cout << 12.34 << endl; // 12.34를 출력
setf()
함수는 바로 이전의 셋팅 값을 반환하기 때문에 그 값을 보관해두었다가 다시 setf()
함수를 호출하면 이전 셋팅으로 돌아갈 수 있는 것이다.
반면에 인자가 하나인 setf()
함수를 사용했다면 unset()
함수를 사용하면 된다.
cout.setf(ios_base::showpos);
cout << 333 << endl; // +333을 출력
cout.unsetf(ios_bsae::showpos);
cout << 333 << endl; // 333을 출력
setf()
함수 외에도 출력 형식을 지정하는데 사용하는 함수가 몇 개 더 있는데 아주 간단한 것들이다. 처음으로 볼 것은 width()
함수로, 출력하는 값을 몇 칸에 걸쳐서 출력할지를 지정하는 역할을 한다. 다음의 예제처럼 하면 숫자 555를 10칸에 걸쳐서 출력한다. 공백 7칸에 숫자 3칸을 더해 모두 10칸이 되는 것이다.
cout.width(10);
cout << 555 << ", " << 556 << endl; // ________555, 556을 출력
width()
함수의 특징은 딱 한 번의 출력에 대해서만 효력이 있다는 점이다. 그래서 첫번째 정수 555만 10칸에 걸쳐 출력했고, 콤마와 556은 자리 수대로 출력했다.
precision()
함수는 실수의 출력 방식에 따라 다른 의미를 갖는데, ios_base::fixed
를 지정한 경우에는 소수점 이하 자릿 수를 지정하는 용도로 사용할 수 있다. 예를 들어 소수점 이하 둘째 자리까지만 출력하고 싶다면 다음과 같이 할 수 있다.
cout.setf(ios_base::fixed);
cout.precision(2);
cout << 5.55555 << endl; // 5.55처럼 출력한다.
fill()
함수를 사용하면 빈 칸을 채우는 문자를 지정할 수 있다. 기본적으로 공백 문자(space)
가 채워지는데, fill()
함수를 사용해서 다른 문자로 바꿀 수 있다.
cout.fill('*');
cout.width(10);
cout << 555 << endl; // **********555를 출력
조정자는 위의 setf()
함수나 기타 함수들을 호출하는 방법에 지나지 않는다. 예를 들어 조종자
를 사용하면 정수를 16진수
로 출력하기 위해서 다음과 같이 할 수 있다.
cout << hex << 333 << endl; // 14d를 출력
이전에는 hex
옵션 값을 사용하기 위해서 복잡하게 setf()
를 호출했었는데 조정자
를 사용하면 매우 간단하게 끝낼 수 있다. 조정자
는 setf()
함수의 옵션 값들과 이름이 비슷하기 때문에 이름만 보아도 그 용도를 충분히 짐작할 수 있다. 다음 표에 조정자
들의 이름을 나열해 놓았다.
boolalpha
| noboolalpha
showbase
| noshowbase
showpoint
| noshowpoint
showpos
| noshowpos
uppercase
| nouppercase
dec
hex
oct
fixed
scientific
internal
left
right
위를 보면 no~
로 시작하는 이름들이 보이는데, 예를 들어 noboolalpha
는 boolalpha
를 취소하는 의미를 갖게 된다. 조종자들의 내부에서는 결국 setf()
나 unsetf()
함수를 호출한다고 생각하면 된다.
여기에 더해 iosmanip (Input Output Manipulator)
헤더 파일에는 인자를 받을 수 있는 조종자
를 몇 개 더 정의하고 있다. 예를 들어 width()
함수를 호출하는 대신 다음과 같이 조종자
를 사용할 수 있다.
#include <iomanip>
cout << setw(10) << 555 << endl; // __________555를 출력
다음은 iomanip
헤더 파일에 있는 조종자
들인데 이 조종자
들은 모두 인자
가 있다.
값 | 의미 |
---|---|
setioflags | setf()를 사용하는 것과 동일 |
resetiosflags | setf()를 통해 지정한 옵션을 제거 |
setfill | fill() 호출 |
setprecision | precision() 호출 |
setw | width() 호출 |
setbase | 8, 10, 16 중 한 값을 넣어서 출력하는 진법 변경 |
setioflags
와 resetioflags
는 인자로 위에 나오는 옵션 값들을 받는데 setf()
보다 편리하게 사용할 수 있다. 예를 들어 resetioflags
를 사용해서 기존의 옵션으로 되돌리는 것도 다음과 같이 간단하다. setf()
함수를 사용할 때처럼 반환 값을 보관할 필요가 있다.
cout << setioflags (ios_base::scientific) << 12.34 << endl; // 1.234000e+001
cout << resetioflags (ios_base::scientific) << 12.34 << endl; // 12.34
basic_ios
클래스에는 스트림
의 상태를 확인할 수 있는 4개의 멤버 함수가 있다. 각 함수는 bool
값을 반환하며 반환 값의 의미는 다음과 같다.
bool good() const; // true면, 정상적인 상태
bool eof() const; // true면, 파일이나 입력의 끝에 도달
bool fail() const; // true면, 예상치 못한 입력이 들어오는 등의 문제 발생
bool bad() const; // true면, 잘못된 파일 등의 문제 발생
예를 들어, 현재 cin
객체의 상태가 정상적인지 알아보기 위해서 다음과 같이 검사할 수 있다.
if(cin.good()) {
// 정상
}
특히 이 함수들은 cin
객체를 사용해서 정수를 입력 받을 때 유용하게 사용할 수 있다. 정수를 입력 받으려고 하는데 사용자가 문자열을 입력한 경우에는 cin
객체가 실패 상태로 변하고 더 이상 사용할 수 없게 된다. 그렇기 때문에 cin
객체의 상태를 검사하고 다시 정상적인 상태로 되돌리는 작업을 필요로 한다.
cin.clear()
cin.ignore(numeric_limits<streamsize>::max(), '\n');
clear()
함수는 cin
객체의 내부적인 상태를 다시 정상으로 돌리는 역할을 한다. 그렇기 때문에 이 함수만 호출하더라도 cin.good()
함수는 true
를 반환할 것이다. 하지만 이것으로 충분하지 않다. 왜냐하면 cin
객체의 버퍼
에는 아직도 잘못된 데이터가 남아있기 때문이다. 그래서 ignore()
함수를 사용해서 버퍼
에 남은 데이터를 모두 무시해버릴 필요가 있다.
basic_istream& ignore(streamsize _Count, int_type _Delim);
ignore()
함수의 원형은 위와 같다. 첫번째 인자 _Count
는 버퍼에서 무시하려는 데이터의 바이트수를 의미한다. 예를 들어 인자로 10을 넘겨주면 버퍼에서 10바이트를 무시하고 지나간다. 다음번에 cin
객체에서 데이터를 요구하면 10바이트를 지나친 위치에서부터 데이터를 읽게 되는 것이다. streamsize
는 정수 타입을 재정의한 타입에 지나지 않는다.
두번째 인자 _Delim
에는 문자를 하나 넘겨주면 되는데, 이 문자를 만날 때까지만 데이터를 무시하게 된다. 예를 들어 _Count
에 10을, _Delim
에 \n
을 넣어주었다고 하자. 그런데 만약 10바이트를 무시하기 전 \n
을 만나게 되면 거기까지만 무시하게 된다. 즉, 데이터 중에 \n
을 만나거나 10바이트가 될 때까지 무시하라는 뜻이 된다.
_Count
인자로 numeric_limits<streamsize>::max()
를 넘겨주었는데, 이 표현은 streamsize
타입이 가질 수 있는 최대 값을 반환한다. 결국 스트림에 있는 모든 데이터를 지우라는 뜻이 된다.
numeric_lmits<streamsize>::max()
이 표현은 조금 복잡해 보이지만 하나씩 따져보면 쉽게 이해할 수 있다.
우선 numeric_limits
가 템플릿 클래스이고, 템플릿 인자로 streamsize
를 넘겨주었다는 것을 알 수 있다. 그리고 max()
는 numeric_limits
클래스의 정적 멤버 함수(static member function)
라는 것도 알 수 있다.
cin
객체를 사용해서 문자열을 입력 받을 때는 메모리 공간을 미리 확보해두어야 하는 문제가 있다. 사용자가 입력할 문자열의 길이를 예측하는 것은 불가능하기 때문이다. 그래서 동적 할당
을 사용하거나 정적으로 할당하되 입력 받을 문자열의 길이를 제한하는 방법을 사용해야 한다.
파일 입출력
에 사용되는 클래스는 ofstream
과 ifstream
이다. 이 클래스를 역시 실제 클래스는 아니고 다음과 같이 템플릿 클래스를 재정의한 클래스다.
typedef basic_ofstream<char> ofstream;
typedef basic_ifstream<char> ifstream;
즉, ofstream
과 ifstream
객체의 실제 클래스는 basic_ofstream
과 basic_ifstream
이 되는 것이다. 그리고 이 클래스들은 basic_ostream
과 basic_istream
의 자식 클래스가 된다.
class basic_ofstream : public basic_ostream
class basic_ifstream : public basic_istream
파일을 여는 방법은 다음과 같이 두 가지가 있다.
ofstream file1("test.txt");
ofstream file;
file2.open("test.txt");
생성자
혹은 open()
멤버함수를 사용할 수 있는데, 파일 이름만 제공되면 출력 혹은 입력용으로 파일을 생성한다. 그런데 여기에 보다 구체적인 옵션을 제시할 수 있는 방법이 있다. 예를 들면 이미 존재하는 파일을 지우고 새로 만들어서 연다거나, 기존 파일의 끝에 이어서 쓸 수 있게 연다거나 하는 등의 옵션이 있다.
값 | 의미 |
---|---|
app | 파일의 끝에 자료를 추가하기 위한 용도로 연다. |
ate | 파일을 열고 파일의 끝으로 이동한다. |
binary | 텍스트(text)가 아닌 바이너리(binary)로 입출력을 한다. |
in | 파일에서 값을 읽기 위한 용도로 연다. |
out | 파일에 값을 쓰기 위한 용도로 연다. |
truc | 기존 파일이 있다면 지워버리고 새 파일을 연다. |
별다른 옵션 없이 파일의 이름만을 제공해서 파일을 열면, 다음과 같이 해준 것과 같은 효과가 있다.
ofstream file("test.txt", ios_base::out | ios_base::trunc);
그렇기 때문에 파일 이름만 제공한다면 기존 파일이 삭제되면서 새 파일이 열리는 것이다. 예를 들어 기존 파일을 지우고 새로 만드는 대신 기존 파일의 끝에 이어서 쓰고 싶다면 다음과 같이 파일을 열면 된다.
setf()
함수에서 했던 것처럼 비트 단위 OR
연산을 사용해서 여러 옵션을 한 번에 전달할 수 있다.
ofstream file("test.txt", ios_base::out | ios_base::app);
file << "test data" << endl;
파일을 연 다음에는 파일이 잘 열린 상태인지 확인할 필요가 있다. 지정한 파일이 존재하지 않거나, 파일에 문제가 있다면 실패할 수 있기 때문이다. 이때는 is_open()
함수를 사용해서 파일이 잘 열였는지 확인해볼 수 있다.
ofstream file("test.txt");
if(false == file.is_open()) {
// 파일을 여는데 실패.
}
그리고 파일을 다 사용한 후에는 close()
함수를 호출해서 파일을 닫아줄 필요가 있다.
file.close();
하지만 ofstream
, ifstream
클래스의 소멸자에서 자동적으로 close()
함수를 호출하기 때문에 굳이 close()
함수를 호출해줄 필요는 없다. 물론 객체가 소멸되기 전에 함수를 빨리 닫을 필요가 있다면 직접 호출해주는 것이 좋다.