C++의 스마트 포인터
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 15번째.
스마트 포인터(Smart pointers)는 힙 메모리를 자동으로 관리해 주는 래퍼 클래스입니다. 포인터가 범위를 벗어날 때 메모리를 정리함으로써 수동으로 delete를 호출할 필요를 없애줍니다.
스마트 포인터를 사용하려면 <memory> 헤더를 포함하세요.
unique_ptr - 독점적 소유권. 한 번에 하나의 포인터만 리소스를 소유할 수 있습니다.
#include <memory>
std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack(); // 일반 포인터처럼 사용
// 복사할 수 없지만, 소유권을 이전할 수 있음
std::unique_ptr<Player> player2 = std::move(player);
// player는 이제 nullptr임shared_ptr - 공유 소유권. 여러 포인터가 동일한 리소스를 소유할 수 있습니다. 마지막 소유자가 소멸될 때 메모리가 해제됩니다.
std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1; // 둘 다 리소스를 소유합니다
std::cout << p1.use_count(); // 2를 출력합니다weak_ptr - shared_ptr의 소유권이 없는 관찰자입니다. 순환 참조를 끊는 데 유용합니다.
std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;
if (auto locked = weak.lock()) { // shared_ptr로 변환
locked->attack();
}단일 소유권을 위해 기본적으로 unique_ptr을 사용하세요. 여러 객체가 리소스를 공유해야 할 때는 shared_ptr을 사용하세요. 수명을 연장하지 않고 관찰하려면 weak_ptr을 사용하세요.
raw new보다는 make_unique와 make_shared를 사용하는 것이 좋습니다.
챌린지
쉬움스마트 포인터의 다양한 소유권 모델을 보여주는 문서 공유 시스템을 구축해 보겠습니다. unique_ptr이 독점적 소유권을 강제하는 방법, shared_ptr이 여러 소유자를 허용하는 방법, 그리고 weak_ptr이 수명에 영향을 주지 않고 관찰하는 방법을 배우게 됩니다.
코드를 구성하기 위해 두 개의 파일을 생성합니다:
Document.h: 공유 가능한 문서를 나타내는Document클래스를 정의합니다. 다음을 포함해야 합니다:- 프라이빗
title속성 (string) - 제목을 매개변수로 받아
"Document created: <title>"를 출력하는 생성자 "Document deleted: <title>"를 출력하는 소멸자- 제목을 반환하는
getTitle()메서드
- 프라이빗
main.cpp: 입력으로부터 문서 제목을 읽어 세 가지 스마트 포인터 유형을 모두 시연합니다:- 입력받은 제목으로 Document에 대한
unique_ptr을 생성합니다. "Unique owner: <title>"를 출력합니다.std::move를 사용하여 소유권을 다른unique_ptr로 이전합니다."Ownership transferred"를 출력합니다.- 제목이
"SharedDoc"인 새 Document에 대한shared_ptr을 생성합니다. - 동일한 문서를 가리키는 두 번째
shared_ptr을 생성합니다. use_count()를 사용하여"Shared owners: <count>"를 출력합니다.- 공유 포인터 중 하나로부터
weak_ptr을 생성합니다. lock()을 사용하여 약한 포인터를 통해 문서에 접근하고"Weak access: <title>"를 출력합니다.
- 입력받은 제목으로 Document에 대한
스마트 포인터를 사용하려면 <memory>를 포함해야 함을 기억하세요. 스마트 포인터를 생성할 때는 std::make_unique와 std::make_shared를 사용하세요. 소멸자 메시지는 프로그램이 끝날 때 각 문서가 언제 자동으로 정리되는지 확인하는 데 도움이 됩니다.
main.cpp에 #include "Document.h"를 사용하여 헤더 파일을 포함하세요.
치트 시트
스마트 포인터는 힙 메모리를 자동으로 관리하는 래퍼 클래스입니다. 이를 사용하려면 <memory> 헤더를 포함하세요.
unique_ptr
독점적 소유권 - 한 번에 하나의 포인터만 리소스를 소유할 수 있습니다:
std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack(); // 일반 포인터처럼 사용
// std::move를 사용하여 소유권 이전
std::unique_ptr<Player> player2 = std::move(player);
// player는 이제 nullptr입니다shared_ptr
공유 소유권 - 여러 포인터가 동일한 리소스를 소유할 수 있습니다. 마지막 소유자가 소멸될 때 메모리가 해제됩니다:
std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1; // 둘 다 리소스를 소유함
std::cout << p1.use_count(); // 2를 출력함weak_ptr
shared_ptr를 소유하지 않고 관찰하는 관찰자입니다. 순환 참조를 끊는 데 유용합니다:
std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;
if (auto locked = weak.lock()) { // shared_ptr로 변환
locked->attack();
}권장 사항: 단일 소유권의 경우 기본적으로 unique_ptr를 사용하세요. 여러 객체가 리소스를 공유해야 할 때는 shared_ptr를 사용하세요. 수명을 연장하지 않고 관찰하려면 weak_ptr를 사용하세요. 가급적 원시 new 대신 make_unique와 make_shared를 사용하세요.
직접 해보기
#include <iostream>
#include <memory>
#include <string>
#include "Document.h"
using namespace std;
int main() {
string inputTitle;
cin >> inputTitle;
// TODO: inputTitle을 사용하여 Document에 대한 unique_ptr 생성
// std::make_unique 사용
// TODO: "Unique owner: <title>" 출력
// TODO: std::move를 사용하여 다른 unique_ptr로 소유권 이전
// TODO: "Ownership transferred" 출력
// TODO: 제목이 "SharedDoc"인 새로운 Document에 대한 shared_ptr 생성
// std::make_shared 사용
// TODO: 동일한 문서를 가리키는 두 번째 shared_ptr 생성
// TODO: use_count()를 사용하여 "Shared owners: <count>" 출력
// TODO: shared pointers 중 하나로부터 weak_ptr 생성
// TODO: lock()을 사용하여 weak_ptr를 통해 문서에 접근
// 그리고 "Weak access: <title>" 출력
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.