1. 스마트 포인터
- 동적으로 할당된 메모리를 자동으로 해제시켜주는 클래스
1) auto_ptr
- 동적으로 할당된 메모리도 자동으로 해제하는 기능을 가진 포인터 래퍼 클래스.
- memory 헤더 파일을 포함시켜야 한다.
#include <memory>
- 단점
> malloc으로 할당한 경우는 자동 해제를 못 한다.
(이 경우 새로 클래스를 만들어야 한다)
> <>에 [] 연산자를 지원하지 않는다.
- 선언 형태
auto_ptr<자료형> 변수명(new 자료형);
- auto_ptr은 포인터와 같이 4 byte를 가진다.
2) unique_ptr
- 하나의 스마트 포인터만이 특정 객체를 소유할 수 있도록 객체에 소유권 개념을 도입한 스마트 포인터.
- shard_ptr과 달리 참조 카운트가 1을 넘을 수 없다.
> unique_ptr로 할당한 메모리는 딱 하나의 포인터 변수로만 해당 객체를 가리킬 수 있다.
> 두 개 이상의 포인터가 하나의 공간을 가리키면 컴파일 에러가 난다.
> 따라서 참조 카운트 포인터가 필요없어 4 byte의 크기를 가진다.
- 선언 형태
unique_ptr<자료형> 변수명(new 자료형);
- 객체 선언 형태
shared_ptr<자료형> 변수명 = make_unique<자료형>(생성자 매개 변수);
- 객체 = move(객체);
> 소유권을 이전하는 함수
- 객체.reset()
> 가지고 있는 메모리 영역을 해제 하는 함수
- auto_ptr, shard_ptr 과는 달리 <>에 []를 지원한다.
3) shared_ptr
- 한 자원을 여러 포인터가 가리킬 때 쓰는 포인터
- 참조 카운트를 통해 참조 카운트가 0이 되는 순간 메모리를 해제한다.
> 참조 카운트 : 해당 메모리를 참조하는 포인터가 몇 개 인지를 나타내는 값.
> 이 참조 카운트는 참조 횟수를 관리하는 객체 Control Block에 저장해 두기 때문에 용량이 늘지 않는다.
- 컨테이너에서 포인터 복사본을 반환 시 원본을 유지하고 싶을 경우 사용.
> 가리키는 주소의 메모리는 모든 소유자가 없어지기 전까지(참조 카운트가 0이 될 때까지) 삭제되지 않는다.
- 선언 형태
shard_ptr<자료형> 변수명(new 자료형);
- 객체 선언 형태
shard_ptr<자료형> 변수명 = make_shard<자료형>(생성자 매개 변수);
- 객체.use_count()
> 참조 카운트를 반환하는 함수
- shared_ptr는 <>에 []를 지원하지 않기 때문에 <Type>(new Type[])형태로 배열을 선언
> [] 연산자를 지원하지 않는다.
> auto 키워드를 이용하면 이를 극복할 수 있다.
* new 선언과 make_shared를 이용한 shard_ptr 선언의 차이점
- (new Type)으로 선언한 경우 Type 할당과 컨트롤 블록 공간 할당의 두 가지 할당을 따로 진행한다.
- make_shared<Type>()할당의 경우 Type 할당과 컨트롤 블록 할당 두 가지를 동시에 진행한다.
따라서 make_shared 할당이 더 빠르고 처리 순서로 인한 문제를 발생하지 않아 안전하다.
* shard_ptr의 경우 8 byte를 가진다.
- 가리키는 객체의 포인터(4 byte) + 컨트롤 블록을 가리키는 포인터(4 byte)
* 컨트롤 블록이 생성되는 조건
1) make_shared로 shared_ptr을 생성한 경우
2) 소유권이 보장된 unique_ptr, auto_ptr로 부터 shared_ptr이 생성된 경우
(아직 공유되지 않은 특정 객체를 공유하겠다고 선언하는 것)
3) raw pointer가 다른 shard_ptr에 따로 공유된 적이 없을 때 shard_ptr이 만들어 졌을 경우
> 이미 공유된 자원은 shard_ptr 또는 weak_ptr을 사용해야 한다.
> 다른 shard_ptr에 공유된 적이 있는 raw pointer로 shared_ptr을 만들면 중복 컨트롤러 발생
따라서 shard_ptr을 생성할 때 raw pointer를 쓰지 않는 것이 좋음.
* 순환 참조로 메모리 누수가 발생할 수 있다.
- 서로 상대방을 가리키는 shared_ptr을 가지고 있으면 참조 횟수는 절대 0이 되지 않는다.
* shard_ptr의 라이프 타임은 프로그램이 종료될 때 메모리 할당이 해제된다.
3) weak_ptr
- shared_ptr와 함께 사용할 수 있는 (참조자 역할, shared_ptr의 객체만 참조) 스마트 포인터
- shared_ptr의 객체를 weak_ptr로 참조하면 shared_ptr의 참조 카운트가 아닌 weak_ptr 참조 카운트가 증가.
- shared_ptr로만 변환 가능하며 weak_ptr, shared_ptr로만 복사 생성, 대입 연산이 가능하다.
- weak_ptr는 해당 객체에 직접적인 접근이 불가능하다.
> lock()함수를 통해 shared_ptr롤 변환한 뒤 get 함수로 접근할 수 있다.
- expired() 함수로 참조하고 있는 shard_ptr의 상태를 체크 할 수 있다.
> 참조한 shared_ptr가 소멸되었으면 true, 살아있으면 false 반환
- shared_ptr의 순환 참조를 제거하기 위해 사용된다.
> 서로가 상대방을 가리키는 shard_ptr을 가지고 있으면 참조 횟수는 절대 0이 되지 않는다.
> weak_ptr일 경우 참조 횟수에 포함되지 않으므로 누수가 일어나지 않음.
4) boost::scoped_ptr
- 범위를 벗어나면 메모리를 해제하는 스마트 포인터 (범위 제한적)
- namespace boost 에서 제공하는 스마트포인터
- scoped_ptr은 복사할 수 없다.
따라서 scoped_ptr을 멤버로 가지고 있는 객체도 복사할 수 없다.
'Language > C++' 카테고리의 다른 글
[C++] 입출력 속도 (0) | 2020.12.13 |
---|---|
[C++] 얕은 복사와 깊은 복사 (0) | 2020.12.13 |
[C++] 가상함수 (0) | 2020.12.13 |
[C++] 선언과 정의 (0) | 2020.12.13 |
[C++] 변수 크기와 sizeof() 연산 (0) | 2020.12.13 |