일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- LEVEL2
- Flyweight Pattern
- Modern C++
- 8-Puzzle
- two pointer
- Unity
- Euclidean
- stack
- effective C++
- dirtyflag pattern
- Project
- 프로세스 상태
- 3D RPG
- SWEA
- Gold
- level1
- Zenject
- knapsack Problem
- PrefixSum
- level3
- algorithm
- binary search
- Bronze
- programmers
- solid 원칙
- Silver
- BFS
- BOJ
- 프로그래머스
- trie
- Today
- Total
Patrick's Devlog
[Modern C++] Smart Pointer 본문
개요
급히 Modern C++에 대해 공부해야할 일이 생겨 간단하게 인터넷을 통해서 숙지하고자 게시글을 정리한다. 자료는 TCP School에서 참고하여 정리하였으며, 좀 더 자세한 내용을 확인하고 싶으면 아래 참고 자료 링크에 들어가면 된다.
스마트 포인터?
C++에서 new 키워드를 사용해 동적으로 할당받은 메모리는 반드시 delete를 사용해 해제해야 한다. C++에서는 메모리 누수로부터 프로그램 안전성을 보장하기 위해 스마트포인터를 제공한다.
스마트 포인터는 포인터처럼 동작하는 클래스 템플릿으로, 사용이 끝난 메모리를 자동으로 해제해준다.
◆ 동작
보통 new 키워드를 이용해 원시 포인터가 실제 메모리를 가리키도록 초기화한 후 원시 포인터를 스마트 포인터에 대입하여 사용한다. 정의된 스마트 포인터의 수명이 다하면, 소멸자는 delete를 이용해 할당된 메모리를 해제해준다. 따라서 new 키워드가 반환하는 주소값을 스마트 포인터에 대입하면 메모리를 해제할 필요가 없어진다.
◆ 종류
C++11 이전에는 auto_ptr을 이용해 수행해왔지만 C++11 이후 auto_ptr은 사라지고 unique_ptr, shared_ptr, weak_ptr을 사용한다. 스마트 포인터는 memory 헤더파일에 정의되어 있다.
unique_ptr
하나의 스마트 포인터만이 특정 객체를 소유할 수 있도록 객체에 소유권 개념을 도입한 스마트 포인터이다. 이 스마트 포인터는 해당 객체의 소유권을 지니고 있을 때만 소멸자가 해당 객체를 삭제할 수 있다. unique_ptr 인스턴스는 move() 멤버 함수를 통해 소유권을 이전할 수 있지만 복사할 수는 없다. 또한 소유권이 이전되면 전에 사용하던 unique_tr 인스턴스는 더이상 해당 객체를 소유하지 않게 재설정된다.
unique_ptr<int> ptr01(new int(5)); // int형 unique_ptr 선언 및 초기화
auto ptr02 = move(ptr01); // ptr01에서 ptr02로 소유권 이전
// unique_ptr<int> ptr03 = ptr01; // 대입 연산자를 이용한 복사는 오류 발생
ptr02.reset(); // ptr02가 가리키고 있는 메모리 영역 삭제
ptr01.reset(); // ptr01이 가리키고 있는 메모리 영역 삭제
보통 C++ 객체에 대해 스마트 포인터가 필요한 상황에서 주로 unique_ptr을 사용하면 된다.
make_unique()
C++14 이후부터 제공되는 make_unique() 함수를 사용하면 unique_ptr 인스턴스를 안전하게 생성할 수 있다. make_unique() 함수는 전달받은 인수를 사용해 지정된 타입의 객체를 생성하고, 생성된 객체를 가리키는 unique_ptr을 반환한다. 이 함수를 사용하면 예외 발생에 대해 안전하게 대처할 수 있다.
아래의 예제는 Person 객체를 가리키는 hong이라는 unique_ptr를 make_unique() 함수를 통해 생성하는 예제이다.
#include <iostream>
#include <memory>
using namespace std;
class Person {
private:
string name_;
int age_;
public:
Person(const string& name, int age);
~Person() { cout << "소멸자가 호출되었습니다." << endl; }
void ShowPersonInfo();
};
int main(void) {
unique_ptr<Person> hong = make_unique<Person>("길동", 29);
hong->ShowPersonInfo();
return 0;
}
Person::Person(const string& name, int age) { // 기초 클래스 생성자의 정의
name_ = name;
age_ = age;
cout << "생성자가 호출되었습니다." << endl;
}
void Person::ShowPersonInfo() { cout << name_ << "의 나이는 " << age_ << "살입니다." << endl; }
Person을 가리키는 unique_ptr 인스턴스인 hong은 사용이 끝난 후 delete를 이용할 필요가 없다.
shared_ptr
하나의 특정 객체를 참조하는 스마트 포인터가 총 몇개인지 참고하는 스마트 포인터이다. 이렇게 참조하고 있는 스마트 포인터의 개수를 참조 횟수(reference count)라고 한다. 참조 횟수는 특정 객체에 새로운 shared_ptr이 추가될 때마다 1씩 증가하며 수명이 다할때마다 1씩 감소한다. 수명이 다해 참조 횟수가 0이되면 delete 키워드를 사용해 메모리를 자동으로 해제한다.
shared_ptr<int> ptr01(new int(5)); // int형 shared_ptr 선언 및 초기화
cout << ptr01.use_count() << endl; // 1
auto ptr02(ptr01); // 복사 생성자를 이용한 초기화
cout << ptr01.use_count() << endl; // 2
auto ptr03 = ptr01; // 대입을 통한 초기화
cout << ptr01.use_count() << endl; // 3
use_count() 멤버 함수는 shared_ptr 객체가 현재 가리키고 있는 리소스를 참조중인 소유자의 수를 반환해준다.
make_shared()
위와 같은 방법 이외에도 make_shared()를 사용하면 shared_ptr 인스턴스를 안전하게 생성할 수 있다. make_shared() 함수는 전달받은 인수를 사용해 지정된 타입의 객체를 생성하고, 생성된 객체를 가리키는 shared_ptr을 반환한다. 이 함수를 사용하면, 예외 발생에 대해 안전하게 대처할 수 있다.
#include <iostream>
#include <memory>
using namespace std;
class Person {
private:
string name_;
int age_;
public:
Person(const string& name, int age);
~Person() { cout << "소멸자가 호출되었습니다." << endl; }
void ShowPersonInfo();
};
int main(void) {
shared_ptr<Person> hong = make_shared<Person>("길동", 29);
cout << "현재 소유자 수 : " << hong.use_count() << endl; // 1
auto han = hong;
cout << "현재 소유자 수 : " << hong.use_count() << endl; // 2
han.reset(); // shared_ptr인 han을 해제함.
cout << "현재 소유자 수 : " << hong.use_count() << endl; // 1
return 0;
}
Person::Person(const string& name, int age) { // 기초 클래스 생성자의 정의
name_ = name;
age_ = age;
cout << "생성자가 호출되었습니다." << endl;
}
void Person::ShowPersonInfo() { cout << name_ << "의 나이는 " << age_ << "살입니다." << endl; }
위의 예제는 Person 객체를 가리키는 hong이라는 shared_ptr를 make_shared() 함수를 통해 생성하는 예제이다.
weak_ptr
하나 이상의 shared_ptr 인스턴스가 소유하는 객체에 대해 접근을 제공하지만, 소유자의 수는 포함되지 않는 스마트 포인터이다.
shared_ptr는 참조 횟수를 기반으로 동작하는 스마트 포인터이며, 서로가 상대방을 가리키는 shared_ptr를 가지고 있다면 참조 횟수는 절대 0이 되지 않으므로 메모리는 영원히 해제되지 않는다. 이렇게 서로가 상대방을 참조하고 있는 상황을 순환 참조(circular reference)라고 한다. weak_ptrㅇ느 이러한 shared_ptr 인스턴스 사이 순환 참조를 제거하기 위해 사용된다.
참고 문헌
http://www.tcpschool.com/cpp/cpp_template_smartPointer
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com
'Programming Language > C++' 카테고리의 다른 글
[Effective C++] Chapter 2 정리 - 1 (0) | 2022.05.26 |
---|---|
[Modern C++] Lvalue 및 Rvalue (0) | 2022.05.20 |
[Modern C++] 시작하기 (0) | 2022.05.16 |
[Effective C++] Chapter 1 정리 - 2 (0) | 2022.05.11 |
[Effective C++] Chapter 1 정리 - 1 (0) | 2022.05.09 |