Computer Security

#11 C++ 스마트 포인터 본문

프로그래밍/C++

#11 C++ 스마트 포인터

쿠리 Kuri 2022. 6. 22. 18:30

스마트 포인터
C++의 스마트 포인터(Smart Pointer)는 프로그래머의 실수로 메모리 누수(Memory Leak)을 방어하기 위한 수
단으로, 포인터처럼 동작하는 클래스 템플릿(Class Template)이다.
기본적으로 힙 영역에 동적 할당된 메모리를 해제하기 위해서는 delete 키워드를 쓰면 된다.

스마트 포인터를 이용하면 메모리 누수를 더 효과적으로 방지할 수 있기 때문에 컴퓨터 시스템의 안정성을 높일 수 있다.

일반적으로 new 키워드를 이용해서 기본 포인터가 특정한 메모리 주소를 가리키도록 초기화 한 이후에 스마트 포인
터에 해당 포인터를 넣어서 사용할 수 있다.
이렇게 정의된 스마트 포인터는 수명을 다했을 때 소멸자가 delete 키워드를 이용해 할당된 메모리들을 자동으로 해
제하는 기능을 수행한다.

 

종류

- unique_ptr: 하나의 스마트 포인터가 특정한 객체를 처리할 수 있도록 한다.
- shared_ptr: 특정한 객체를 참조하는 스마트 포인터가 총 몇 개인지를 참조한다.
- weak_ptr: 하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대한 접근을 제공한다.

 

 


unique_ptr
C++에서 하나의 스마트 포인터만이 특정한 객체를 처리하도록 할 때 unique_ptr를 사용할 수 있다.
이러한 스마트 포인터는 특정한 객체의 소유권을 가지고 있을 때만 소멸자가 객체를 삭제할 수 있다.

 

unique_ptr: 소유권 이전과 메모리 할당 해제

 

코드 예시

#include <iostream>

using namespace std;

int main(void) {
	unique_ptr<int> p1(new int(10)); //p1에 10이라는 동적할당 메모리가 선언가르켜진 상태.
	unique_ptr<int> p2; //여긴 지금은 아무것도 가르켜지지 않은 상태이다.
	cout << "스마트 포인터 1: " << p1 << '\n'; //10에대한 메모리값 반환
	cout << "스마트 포인터 2: " << p2 << '\n'; // 0 
	cout << "--- 소유권 이전 ---\n";
	p2 = move(p1); // move 함수를 이용해 소유권을 p1에서  p2로  이전한다. 
	cout << "스마트 포인터 1: " << p1 << '\n';  // 0 
		cout << "스마트 포인터 2: " << p2 << '\n'; // 10에대한 메모리값이 반환
		cout << "--- 메모리 할당 해제 ---\n"; 
	p2.reset(); // reset함수를 이용해 메모리 할당 해제 
	cout << "스마트 포인터 1: " << p1 << '\n'; // 0 
	cout << "스마트 포인터 2: " << p2 << '\n'; // 0
	system("pause");
}

결과 값

unique_ptr: 객체에 접근하기

 

코드 예시

#include <iostream>

using namespace std;

int main(void) {
unique_ptr<int> p1(new int(10));
cout << *p1 << '\n'; // 관리하고 있는 객체를 반환합니다.
system("pause");
}

결과 값

 

unique_ptr: 메모리 해제 이후에 객체 접근

 

코드 예시

#include <iostream>

using namespace std;

int main(void) {
	int* arr = new int[10]; //10동적메모리 할당
	unique_ptr<int> p1(arr); //그걸 p1이라는 유니크 포인터가 가르킴
	for (int i = 0; i < 10; i++) {
		arr[i] = i;
	} //잘 출력되겠지?
	for (int i = 0; i < 10; i++) {
		cout << arr[i] << ' ';
	}
	p1.reset(); //동적 메모리 할당을 해제 해버림.
	cout << '\n';
	for (int i = 0; i < 10; i++) {
		cout << arr[i] << ' '; //쓰레기 값 나옴
	}
	system("pause");
}

 

결과 값


shared_ptr
C++에서 shared_ptr은 하나의 특정한 객체를 참조하는 스마트 포인터의 개수가 몇 개인지를 참조한다.
특정한 객체를 새로운 스마트 포인터가 참조할 때마다 참조 횟수(Reference Count)가 1씩 증가하며, 각 스마트 포
인터의 수명이 다할 때마다 1씩 감소한다.

결과적으로 참조 횟수가 0이 되면 delete 키워드를 이용해 메모리에서 데이터를 자동으로 할당 해제한다.

 

use_count는 현재 참조하고 있는 객체의 개수를 나타내준다.

 

코드 예시

#include <iostream>

using namespace std;

int main(void) {
	int* arr = new int[10]; //10 메모리 할당
	shared_ptr<int> p1(arr); // p1이 arr메모리 가르킴
	cout << p1.use_count() << '\n'; // p1 한개 밖에 안가르키는중 
		shared_ptr<int> p2(p1); //p2도 p1을 가르킴 현재 그럼 arr는 p1 p2둘다 가르키는중
	cout << p1.use_count() << '\n'; // p1 p2 두개가 가르키는중 
		shared_ptr<int> p3 = p2; //이번엔 p3도 가르킨대
	cout << p1.use_count() << '\n'; //p1 p2 p3 총 3개가 가르킴
	p1.reset(); 
	p2.reset();
	p3.reset(); //p1 p2 p3 전부 메모리할당 해제
	cout << p1.use_count() << '\n'; //전부 메모리가 할당해제됐으니, 가르키는건 없다. 즉 0 도출
		system("pause");
}

결과 값


weak_ptr
C++에서 weak_ptr은 하나 이상의 shared_ptr 객체가 참조하고 있는 객체에 접근할 수 있다.

하지만 해당 객체의 소유자의 수에는 포함되지 않는 스마트 포인터다.
일반적으로 서로가 상대방을 가리키는 두 개의 shared_ptr이 있다면, 참조 횟수는 0이 될 수 없기 때문에 메모리에
서 해제될 수 없다.

weak_ptr은 이러한 순환 참조(Circular Reference) 현상을 제거하기 위한 목적으로 사용할 수 있다.

 

코드 예시

#include <iostream>

using namespace std;

int main(void) {
	int* arr = new int(1);
	shared_ptr<int> sp1(arr);
	weak_ptr<int> wp = sp1; // wp는 참조 횟수 계산에서 제외한다.
	cout << sp1.use_count() << '\n'; // 1로 동일하다.
	cout << wp.use_count() << '\n';
		if (true) {
			shared_ptr<int> sp2 = wp.lock(); // shared_ptr 포인터 반환
			cout << sp1.use_count() << '\n';
				cout << wp.use_count() << '\n';
		}
	// 스코프(Scope)를 벗어나므로 sp2가 해제됩니다.
	cout << sp1.use_count() << '\n';
		cout << wp.use_count() << '\n';
		system("pause");
}

 

결과 값

 

 

'프로그래밍 > C++' 카테고리의 다른 글

#13 C++ STL 시퀀스 컨테이너 라이브러리  (0) 2022.06.24
#12 C++ STL 컨테이너 어댑터 라이브러리  (0) 2022.06.23
#10 C++ 템플릿  (0) 2022.06.21
#9 다형성 기법 2  (0) 2022.06.20
#8 C++ 다형성 기법 1  (0) 2022.06.19
Comments