스마트 포인터(Smart pointer)

sua·2022년 4월 11일
0

명품 C++ Programming

목록 보기
5/10
post-thumbnail

Smart Pointer : C++ 일반 포인터를 모방한 템플릿 타입의 객체, C++ class => 문법과 의미에서 C++ 일반 포인터와 같음

<차이점>

1) 동적 메모리 공간(힙or자유공간)에 할당된 메모리의 주소만 저장 가능

2) Automatic cleanup : 자유공간에 할당된 메모리가 더 필요하지 않을 때 메모리가 자동으로 해제(delete를 사용하지 않아도 됨) => 메모리 누수 발생 가능성을 제거

3) Automatic initialization : 스마트 포인터를 NULL로 초기화할 필요 없음

4) memory management나 locking 등 좀 더 유용 : Dangling pointers, Exception(try/catch) safety, Garbage collection

5) 일반 포인터에서 하던 증가/감소 같은 산술연산을 할 수 없음

6) 헤더를 포함해야 함


<종류>

1) auto_ptr : 포인터 변수와 비슷하게 동작하는 객체로써, 가리키고 있는 대상(동적 할당된 대상)에 대해 auto_ptr 클래스의 소멸자가 자동으로 delete를 호출하는 클래스

  • 복사 시 소멸식 복사를 하기 때문에 소유권을 이전함 => STL 컨테이너에 사용하면 문제 생기므로 사용 x / 내재된 포인터에 대해 오직 하나만의 소유만을 허용

2) unique_ptr : auto_ptr과 유사하게 하나의 스마트 포인터만이 특정 객체를 소유할 수 있도록, 객체에 소유권 개념을 도입한 스마트 포인터이나 복사 생성자와 대입 연산자가 제공되지 않기 때문에 복사를 할 수 없음 => unique_ptr은 스스로 포인터의 유일성을 보장

  • std::movd() 멤버 함수를 통해 소유권을 이전할 수는 있지만 복사할 수는 없다. 소유권 해제 시점은 포인터 객체가 가리키는 객체의 소멸, reset메소드에서 명시적 호출을 통해 값을 변경할 때

3) shared_ptr : 하나의 특정 객체를 참조하는 스마트 포인터가 총 몇 개인지 참조하는 참조 카운팅 방식의 스마트 포인터(RCSP : Reference-Counting SP)

  • 가리키고 있는 객체에 대해 소유권을 가지지 않고 참조카운트만 유지하는 포인터
    • 다른 객체를 가리키면서 포인터에 대한 소유권을 공유(aliasing)
    • 자원을 참조하는 외부 객체의 개수를 관리하고 있다가 그 개수가 0이 되면 해당 자원을 자동으로 삭제
  • STL 컨테이너 사용이 가능
  • Garbage Collection의 동작과 흡사하지만, Garbage Collection과는 달리 참조 상태가 고리를 이루는 경우 (서로 다른 두 객체가 서로를 참조하는 경우)는 없앨 수 없음

4) weak_ptr : shared_ptr의 순환 참조로 발생하는 문제를 해결하기 위해 사용하는 특수한 포인터

  • weak_ptr은 shared_ptr 관리하기 위한 참조카운트에 포함되지 않고 shared_ptr의 객체를 참조만 함 (shared_ptr의 weak reference count로 관리)
  • 약한 참조 성질을 지님(객체가 살아있도록 유지시키지 않고, 단순히 객체가 살아있는 동안만 참조 가능)
  • expired 함수를 통해 자신이 참조하고 있는 shared_ptr의 상태를 확인 가능
  • weak_ptr 객체는 포인터에 대해 직접 접근이 불가능
    • 액세스를 원하면 lock 메소드를 통해 shared_ptr로 변환한 뒤, shared_ptr의 get 메소드를 사용
#include<iostream>
#include<memory>
using namespace std;

int main() {
    shared_ptr<int> sp1(new int(5));
    weak_ptr<int> wp1 = sp1;

    cout << "weak_ptr<int> wp1=sp1;" << endl;
    cout << "sp1:" << sp1.use_count() << endl;
    cout << "(" << *sp1 << ")" << endl;
    cout << "Wp1:" << wp1.use_count() << endl << endl;
    {
        shared_ptr<int> sp2 = wp1.lock();
        cout << "shared_ptr<int> sp2 = wp1.lock();" << endl;
        cout << "sp1: " << sp1.use_count() << endl;
        cout << "wp1: " << wp1.use_count() << endl;
        cout << "sp2: " << sp2.use_count() << endl;
        cout << "(" << *sp2 << ")" << endl << endl;
    }
    cout << "{} 범위 밖 " << endl;
    cout << "sp1 : " << sp1.use_count() << endl;
    cout << "wp1 : " << wp1.use_count() << endl;

    return 0;
}

< 스마트 포인터를 이용하여 파티 참가자를 관리하는 Party, User 클래스 작성>

#include <iostream>
#include <memory>
#include <vector>
using namespace std;

class User;
class Party;

class Party {
    vector<shared_ptr<User>> memList;
public:
    Party() {}
    ~Party() {
        memList.clear(); // 초기화 삭제
    }
    void addMem(shared_ptr<User>& mem) {
        memList.push_back(mem);
    }
};

class User {
private :
    shared_ptr<Party> mParty;
public :
    void setParty(shared_ptr<Party>& party) {
        mParty = party;
    }
};

int main() {
    shared_ptr<Party> party(new Party);
    weak_ptr<Party> tmp;
    tmp = party;
    cout << "for 이전 : " << tmp.use_count() << endl;
    for (int i = 0; i < 5; i++) {
        shared_ptr<User> user(new User);
        party->addMem(user);
        user->setParty(party);
        cout << i + 1 << "명 : " << tmp.use_count() << endl;
    }
    cout << tmp.use_count() << endl;
    party.reset();
    cout << "party.reset() 이후 : " << tmp.use_count() << endl;
    return 0;
}

profile
가보자고

0개의 댓글

관련 채용 정보