unique_ptr 테스트

간단해 보이지만 써보면 뭔가 쓰기 어려웠다. 대충보고 쓰니 그런것 같다. 그래서 한번 혼자 이렇게 저렇게 써봤다.

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

class Item
{
public:
    Item()
    {
        cout << "Item constructor : " << this << endl;
    }

    virtual ~Item()
    {
        cout << "Item destructor : " << this << endl;
    }

    virtual void Print()
    {
        cout << "Item : " << this << endl;
    }
};

class Apple : public Item
{
public:
    Apple(int value)
        : _value(value)
    {
        cout << "Apple constructor : " << this << ", value : " << _value << endl;
    }

    virtual ~Apple()
    {
        cout << "Apple destructor : " << this << ", value : " << _value << endl;
    }

    virtual void Print()
    {
        cout << "Apple : " << this <<", value : "<<_value<< endl;
    }

private:
    int _value{0};
};

class Inventory
{
public:
    void SetItem(unique_ptr<Item> item)
    {
        _item = std::move(item);
    }

public:
    unique_ptr<Item> _item;
};

int main()
{
    unique_ptr<Item> uPtrItem(new Apple(1));    // 기본적으로 생성하는 방법은 이렇다. 
    //unique_ptr<Item> uPtrItem2 = uPtrItem;    // 복사생성자는 삭제됨. 소유권이전은 std::move를 쓴다.
    unique_ptr<Item> uPtrItem2 = move(uPtrItem);

    uPtrItem2->Print();
    uPtrItem2.get()->Print();   // raw pointer는 get으로 접근한다.
    //uPtrItem2.release();  // release은 소유권을 포기한다. 메모리 해제는 않함.
    //uPtrItem2.reset(nullptr);  // reset은 소유한 포인터를 교체한다.
    //uPtrItem2 = move(unique_ptr<Item>(nullptr));// nullptr uniqur_ptr을 넣어서 해제할 수도 있다.
    //uPtrItem2 = move(nullptr);    // 그냥 nullptr을 넣어도 된다
    uPtrItem2 = nullptr;  // 어잉 그냥 nullptr을 넣어도 되네?! (코드를 보니 nullptr_t 대입연산자는 reset을 호출하게 구현)

    cout << "===========" << endl;

    Item* rawItem1 = new Apple(10);
    unique_ptr<Item> uPtrItem3(rawItem1);    // 돌아다니는 rawPointer는 이렇게 잡아다가 생성한다.
    
    Item* rawItem2 = new Apple(11);
    unique_ptr<Item> uPtrItem4;
    //uPtrItem4 = rawItem2;   // 자동 변환 되지 않는다.
    uPtrItem4 = unique_ptr<Item>(rawItem2);   // 미리 생성해둔 unique_ptr에 값을 넣을때는 1.unique_ptr을 생성해서 넣어준다.
    //uPtrItem4.reset(rawItem2);  // 미리 생성해둔 unique_ptr에 값을 넣을때는 2. reset을 호출한다.
    uPtrItem4.reset();

    cout << "===========" << endl;

    Inventory inven;
    //inven.SetItem(new Item());    // 자주 실수한 부분. 매개변수로 넘길때는 raw point 가 unique_ptr 로 자동 변환 되지 않는다.

    inven.SetItem(unique_ptr<Item>(new Item));  // unique_ptr 생성자에 raw pointer 를 넣어서 생성하고 인자로 넘어감
    inven.SetItem(unique_ptr<Apple>(new Apple(20)));    // 하위 클래스도 잘 처리됨
    inven.SetItem(unique_ptr<Item>());  // nullptr 을 넣을수 있고, nullptr을 넣을 경우 소멸자에서 문제없음.
    inven.SetItem(unique_ptr<Item>(nullptr));  // unique_ptr을 초기화 시키고 싶다면,
                                                // 클래스 내부에서 reset를 호출하거나 이렇게 nullptr로 다시 세팅해줄수 있음.
    inven.SetItem(nullptr);   // 어잉 이렇게 해도 되네?! (코드를 보니 nullptr_t 대입연산자는 reset을 호출하게 구현)

    cout << "===========" << endl;

    inven.SetItem(make_unique<Apple>(21));  // make_unique 는 생성자에서 필요한 인자를 받아 직접 생성해서 인자로 넘어감
    inven.SetItem(make_unique<Item>());  // 그래서 make_unique 의미상 nullptr을 넣을순 없음
    inven.SetItem(nullptr);

    cout << "===========" << endl;
}

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다