1. 용어
- 복사 : 객체 생성시 다른 객체로부터 데이터를 복사한다.
- 얕은 복사 : 가리키는 객체의 주소를 복사하여 참조한다.
- 깊은 복사 : 가리키는 객체의 데이터를 복사하여 독립적으로 참조한다.
2. 스마트 포인터
2-0. 포인터 에러
포인터는 할당되지 않은 메모리에 할당해제를 할 경우 런타임 에러가 발생하고
프로그램이 비정상으로 종료되거나 메모리 손상이 발생할 수 있다.
2-1. 포인터 대신 스마트 포인터?
포인터에 저장된 주소만으로 현재 객체가 할당되었는지 할당되지 않았는지 확인할 수 없다.
프로그램이 복잡해지면 여러 포인터가 하나의 객체를 참조하게 되는데 향후 어떤 포인터가 할당 해제할 지 고민하게 된다.
포인터1 : 내가 먼저 할당했음으로 내가 할당 해제를 하지!
포인터2 : 잠시만... 나는 아직 해당 객체를 사용하고 있어.
포인터1 : 그러면 2번이 사용을 끝내고 할당해제할까?
포인터3 : 기다려! 나도 아직 사용 중이야
메모리를 관리하기 위해 어느 순간 할당 해제를 해야한다. 그 순간이란 언제일까?
2-2. 스마트 포인터
위 문제를 해결하기 위해 모든 포인터가 사용을 완료하였는지 확인해야한다.
하지만 수많은 코드에서 현재 어떤 포인터가 객체를 가리키고 있는지 찾아내는 것은 쉽지 않다.
"그러면 객체를 참조하는 포인터들을 기록하자"
스마트 포인터는 포인터를 감싸는 레퍼 클래스이다.
그리고 객체를 몇 명이 참조하고 있는지 기록하고 있으며 이를 레퍼런스 카운터라고 한다.
2-3. 레퍼런스 카운터
레퍼런스 카운터로 어떻게 할당 해제를 안전하게 할 수 있을까?
레퍼런스 카운터는 0이 되면 자동으로 할당해제를 한다.
스마트 포인터1 : 참조 (카운트 1)
스마트 포인터 2 : 참조 (카운트 2)
스마트 포인터 3 : 참조 (카운트 3)
스마트 포인터 2 : 참조 해제 (카운트 2)
스마트 포인터 3 : 참조 해제 (카운트 1)
스마트 포인터 1: 참조 해제 (카운트 0 = 할당 해제)
3. unique_ptr
레퍼런스 카운터를 최대 1까지 허용된다.
하나의 객체를 하나의 포인터만이 참조한다는 것을 보장한다.
unique_ptr 생성
#include <memory>
unique_ptr<int> ptr = make_unique<int>(10);
unique_ptr 소유권 이전 (move)
unique_ptr<int> ptr = make_unique<int>(10);
unique_ptr<int> ptr2 = std::move(ptr);
if (!ptr) cout << "소유권 이전 완료";
Unique_ptr 주의할 점
unique_ptr은 복사가 불가능하다.
복사를 허용하면 레퍼런스 카운터는 2이상이 된다.
unique_ptr<int> ptr2 = ptr1; // 컴파일 에러 발생!
4. shared_ptr
레퍼런스 카운터를 여러개 허용한다.
shared_ptr 생성
#include <memory>
shared_ptr<int> ptr = make_shared<int>(10);
Shared_ptr 레퍼런스 복사
shared_ptr<int> ptr = make_shared<int>(10);
shared_ptr<int> ptr2 = ptr;
shared_ptr 레퍼런스 카운터 개수 확인
ptr.use_count();
shared_ptr 레퍼런스 참조 해제
shared_ptr<int> ptr = make_shared<int>(10); // 레퍼런스 카운트 1
shared_ptr<int> ptr2 = ptr; // 레퍼런스 카운트 2
ptr2.reset(); // 레퍼런스 카운트 1'C++ > Basic' 카테고리의 다른 글
| [C++] 함수 오버로딩과 템플릿 (0) | 2024.12.26 |
|---|---|
| [C++] 객체지향 프로그래밍 (0) | 2024.12.25 |
| [C++] Class (0) | 2024.12.25 |