간단해 보이지만 써보면 뭔가 쓰기 어려웠다. 대충보고 쓰니 그런것 같다. 그래서 한번 혼자 이렇게 저렇게 써봤다.
#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;
}