반응형

c++에서는 new 키워드를 사용해서 동적으로 메모리를 할당합니다.

그리고 이러한 메모리는 반드시 delete 키워드를 사용하여 메모리 할당을 해제합니다.

 

스마트 포인터(smart pointer)란 포인터처럼 동작하는 클래스 템플릿으로, 사용이 끝난 메모리를 자동으로 해제해 줍니다.

 

java에서의 가비지 컬렉션과 같은 역할을 해주는 것입니다.

 

C++11 이전에는 auto_ptr이라는 스마트 포인터를 사용하여 이 작업을 수행하였습니다.

하지만 C++11부터는 다음과 같은 새로운 스마트 포인터를 제공하고 있습니다.

 

  •  unique_ptr
  •  shared_ptr
  •  weak_ptr

 

1. unique_ptr 

 

하나의 스마트 포인터만 특정 객체를 소유하는 것입니다. 해당 스마트 포인터는 move 함수를 통해서 소유권을 이전할  수는 있지만 복사는 불가능합니다.

 

unique_ptr<int> ptr01(new int(5)); // int형 unique_ptr인 ptr01을 선언하고 초기화함.

auto ptr02 = move(ptr01);          // ptr01에서 ptr02로 소유권을 이전함.

// unique_ptr<int> ptr03 = ptr01;  // 대입 연산자를 이용한 복사는 오류를 발생시킴. 

ptr02.reset();                     // ptr02가 가리키고 있는 메모리 영역을 삭제함.

ptr01.reset();                     // ptr01가 가리키고 있는 메모리 영역을 삭제함.

 

 

예시코드입니다.

#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; }

 

실행 결과입니다.

 

생성자가 호출되었습니다.

길동의 나이는 29살입니다.

소멸자가 호출되었습니다.

 

 

자동으로 메모리를 해제해주기 때문에 개발자가 메모리에 대한 신경을 덜 써줘도 되는 장점이 있습니다.

 

2. shared_ptr

 

하나의 특정 객체를 참조하는 스마트 포인터가 총 몇 개인지 참조하는 스마트 포인터입니다.

 

아래는 예시 코드입니다.

shared_ptr<int> ptr01(new int(5)); // int형 shared_ptr인 ptr01을 선언하고 초기화함.

cout << ptr01.use_count() << endl; // 1

auto ptr02(ptr01);                 // 복사 생성자를 이용한 초기화

cout << ptr01.use_count() << endl; // 2

auto ptr03 = ptr01;                // 대입을 통한 초기화

cout << ptr01.use_count() << endl; // 3  

make_shared() 함수를 사용하면 shared_ptr 인스턴스를 안전하게 생성할 수 있습니다.

 

예시 코드입니다.

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

 

3. weak_ptr 

 

하나 이상의 shared_ptr 인스턴스가 소유하는 개체에 대한 접근을 제공하지만 소유자의 수에는 포함되는 않는 스마트 포인터입니다.

 

 

4. enable_shared_from_this

 

 이 친구는 아래와 같은 형태로 사용된다.

class type : public std::enable_shared_from_this<type>
{
public:
    type(){ std::cout << __FUNCTION__ << std::endl;}
    ~type(){ std::cout << __FUNCTION__ << std::endl;}
     
    std::shared_ptr<type> getPtr()
    {
        //return std::shared_ptr<type>(this);
        return shared_from_this();
    }   
};


 

정상적인 동작을 위해서 사용한다.

 

아래코드를 보자

#include <iostream>
#include <memory>
 
class type
{
public:
    type(){ std::cout << __FUNCTION__ << std::endl;}
    ~type(){ std::cout << __FUNCTION__ << std::endl;}
     
    std::shared_ptr<type> getPtr()
    {
        return std::shared_ptr<type>(this);
    }   
};
 
int main()
{
    type *p = new type;
     
    std::shared_ptr<type> ptr1(p); //p object를 가르키는 shared_ptr 생성자 호출
    std::cout <<"ptr1.use_count(): " << ptr1.use_count() << std::endl;
 
    // ptr2에 ptr1에서 객체의 주소를 return 받아 할당한다.
    std::shared_ptr<type> ptr2 = ptr1->getPtr();
    std::cout <<"ptr2.use_count(): " << ptr2.use_count() << std::endl;
     
    return 0;
}


 

type이라는 클래스 하나를 동적선언하고 ptr1에 할당한다. 그리고 ptr1이 사용되지 않기에 메모리를 소멸시키게 되는데 그렇기 때문에 ptr2에서는 오류가 발생한다. (Segmentation fault) 

 

이를 방지하고자 사용된다.

 

#include <iostream>
#include <memory>
 
class type : public std::enable_shared_from_this<type>
{
public:
    type(){ std::cout << __FUNCTION__ << std::endl;}
    ~type(){ std::cout << __FUNCTION__ << std::endl;}
     
    std::shared_ptr<type> getPtr()
    {
        //return std::shared_ptr<type>(this);
        return shared_from_this();
    }   
};
 
int main()
{
    type *p = new type;
     
    std::shared_ptr<type> ptr1(p); //p object를 가르키는 shared_ptr 생성자 호출
    std::cout <<"ptr1.use_count(): " << ptr1.use_count() << std::endl;
 
    // ptr2에 ptr1에서 객체의 주소를 return 받아 할당한다.
    std::shared_ptr<type> ptr2 = ptr1->getPtr();
    std::cout <<"ptr2.use_count(): " << ptr2.use_count() << std::endl;
     
    return 0;
}

 

shared_ptr을 추가할 경우에는 std::enable_shared_from_this 클래스로부터 상속을 받게되는 구조이다.

 

출처: www.tcpschool.com/cpp/cpp_template_smartPointer
출처: https://chipmaker.tistory.com/entry/enablesharedfromthis-정리 [CHIPMAKER]

반응형

+ Recent posts