이번 편의 목표: 파일과 메모리의 해제를 객체의 소멸자에 맡기고, 소유권이 하나뿐인 메모리는 unique_ptr로 표현합니다.
RAII는 자원 획득을 초기화에 묶는 방식입니다. 생성자에서 자원을 얻고, 소멸자에서 돌려줍니다. 함수가 중간에 return해도 스택의 객체는 소멸자가 호출됩니다. 13편에서 실패할 때마다 fclose를 적던 일을 타입이 대신합니다.
#include <cstdio>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
class File {
public:
explicit File(const char *path) : file_(std::fopen(path, "w")) {
if (file_ == nullptr) {
throw std::runtime_error("파일을 열 수 없습니다.");
}
}
~File() {
if (file_ != nullptr) {
std::fclose(file_);
}
}
File(const File &) = delete;
File &operator=(const File &) = delete;
void write(const char *text) {
std::fputs(text, file_);
}
private:
std::FILE *file_;
};
struct Book {
int id;
std::string title;
};
int main() {
File note("note.txt");
note.write("개미\n");
auto book = std::make_unique<Book>();
book->id = 1;
book->title = "개미";
std::cout << book->title << '\n';
return 0;
}File의 복사를 삭제하면 같은 파일 핸들을 가진 객체가 두 개 생기지 않습니다. 핸들을 닫는 소멸자는 하나뿐입니다. main이 끝나면 note의 소멸자가 파일을 닫습니다.
std::unique_ptr은 동적 객체를 하나만 소유합니다. std::make_unique<Book>()이 메모리를 만들고, unique_ptr이 소멸될 때 그 메모리를 돌려줍니다. 복사는 컴파일 오류입니다. 소유권을 넘길 때는 22편의 이동을 사용합니다. 소유하지 않고 들여다보기만 하는 함수에는 Book*나 const Book&를 넘깁니다. 그 포인터로 delete하지 않습니다.
shared_ptr은 소유자를 여럿으로 늘립니다. 진짜로 수명을 공유해야 할 때만 씁니다. 기본 선택은 unique_ptr입니다.
직접 해 보기
Book을 unique_ptr로 하나 더 만들고 제목만 출력한 뒤, 그 포인터를 복사하는 코드가 컴파일되지 않는지 확인하세요.
해설
auto copy = book; 은 unique_ptr의 복사가 막혀 있으므로 컴파일 오류입니다. 두 번째 책은 make_unique로 따로 만듭니다. 각 객체의 메모리는 그 unique_ptr의 수명이 끝날 때 반환됩니다.
COMMENTS
댓글 0
이 글에 대한 의견이나 질문을 남겨 주세요.
댓글은 구글이나 카카오로 시작한 뒤에 남길 수 있습니다.
등록된 댓글이 없습니다.