- class AAA;
- // RAII 방식으로... AAA 객체 생성
- std::auto_ptr<AAA> AAAObject(new AAA());
- // 복사가 되는 순간, AAAObject는 NULL이 되고, 이제 BBBObject 만이 객체를 가리킨다.
- std::auto_ptr<AAA> BBBObject(AAAObject);
- // 역시 대입이 되는 순간, BBB는 NULL, 이제 AAA가 객체를 가리킴.
- AAAObject = BBBObject;
- namespace : std
- header : <memory>
- class Car {...};
- // Resource Acquisition Is Initializing : RAII
- std::shared_ptr<Car> Avante( new Car() );
- 증가 : shared_ptr 객체의 복사나 대입이 발생하여 참조 shared_ptr 객체 수 증가.
- 감소 : shared_ptr이 가리키고 있는 객체를 참조하는 shared_ptr 객체 수의 감소.
- class Car {...};
- // 값 전달, 복사에 의한 임시객체 생성, 함수 종료시 생성된 임시객체 소멸
- // 하지만 아래 매개변수를 const std::shared_ptr<Car>&로 받는다면,
- // 임시 객체가 생기지 않아서 참조 카운트가 올라가지 않는다.
- void function( std::shared_ptr<Car> _car )
- {
- ...
- }
- int main()
- {
- // 최초 생성시 초기 참조 카운트는 당연히 '1'
- std::shared_ptr<Car> Car1( new Car() );
- // 복사 -> 참조 카운트 '2'
- std::shared_ptr<Car> Car2(Car1);
- // 대입 -> 참조 카운트 '3'
- std::shared_ptr<Car> Car3 = Car1;
- // function( std::shared_ptr<Car> _car ), 값에 의한 전달, 복사에 의한 임시객체 생성
- // 이로 인한 참조 카운트 증가 -> '4'
- function( Car3 );
- // 함수 호출 후엔 임시객체 소멸되므로 참조 카운트 감소 -> '3'
- // reset 함수는 shared_ptr이 참조하는 객체를 새로운 녀석으로 바꿀 수 있는 함수이다.
- // 내부적으로 shared_ptr::swap 함수가 사용됨
- // http://msdn.microsoft.com/ko-kr/library/bb982757.aspx
- // 인자를 주지 않으면 참조 포기가 되는 것이다. 따라서 참조 카운트 감소 -> '2'
- Car3.reset();
- ...
- return 0;
- // 함수 반환시 남아있던 shared_ptr 모두 소멸 -> 참조 카운트 '0'
- // 이제 shared_ptr이 참조하고 있던 Car * 에 대해 delete가 호출됨.
- }
- class Car {...};
- // 최초 생성시 초기 참조 카운트는 당연히 '1'
- std::shared_ptr<Car> Car1( new Car() );
- // 최초 생성시 초기 참조 카운트는 당연히 '1'
- std::shared_ptr<Car> Car2( new Car() );
- // Car1 shared_ptr은 이제 Car2의 객체를 참조한다.
- // Car1이 참조하던 Car* 는 더 이상 참조자가 존재하지 않아, delete가 호출된다.
- // 대신 Car2가 참조하던 객체를 이제 Car1 shared_ptr도 참조하므로 참조 카운트는 '2'
- Car1 = Car2;
- template<class _Ux>
- explicit shared_ptr(_Ux *_Px)
- { // construct shared_ptr object that owns _Px
- _Resetp(_Px);
- }
- template<class _Ux, class _Dx>
- shared_ptr(_Ux *_Px, _Dx _Dt)
- { // construct with _Px, deleter
- _Resetp(_Px, _Dt);
- }
- template<class _Ux, class _Dx, class _Alloc>
- shared_ptr(_Ux *_Px, _Dx _Dt, _Alloc _Ax)
- { // construct with _Px, deleter, allocator
- _Resetp(_Px, _Dt, _Ax);
- }
- // deleter 클래스 정의
- template<typename T>
- struct ArrayDeleter
- {
- void operator () (T* p)
- {
- delete [] p;
- }
- };
- // shared_ptr 생성시 두 번째 인자로 deleter class를 넘기면...
- // 아무런 문제없이 객체 배열도 제대로 delete [] 처리가 된다.
- std::shared_ptr<int> spi( new int[1024], ArrayDeleter<int>() );
- template<class _Ty1, class _Ty2>
- shared_ptr<_Ty1> static_pointer_cast(const shared_ptr<_Ty2>& _Other)
- {
- // return shared_ptr object holding static_cast<_Ty1 *>(_Other.get())
- return (shared_ptr<_Ty1>(_Other, _Static_tag()));
- }
- template<class _Ty1, class _Ty2>
- shared_ptr<_Ty1> const_pointer_cast(const shared_ptr<_Ty2>& _Other)
- {
- // return shared_ptr object holding const_cast<_Ty1 *>(_Other.get())
- return (shared_ptr<_Ty1>(_Other, _Const_tag()));
- }
- template<class _Ty1, class _Ty2>
- shared_ptr<_Ty1> dynamic_pointer_cast(const shared_ptr<_Ty2>& _Other)
- {
- // return shared_ptr object holding dynamic_cast<_Ty1 *>(_Other.get())
- return (shared_ptr<_Ty1>(_Other, _Dynamic_tag()));
- }
- class Car {...};
- class Truck : public Car {...};
- // Truck 타입의 객체를 Car 타입의 객체를 참조하는 shared_ptr에 초기화
- shared_ptr<Car> pCar( new Truck() );
- // shared_ptr<Car>가 참조하고 있던 객체를 Truck 타입으로 static_cast하여 대입.
- // 대입 하였기에 참조 카운트는 '2'
- shared_ptr<Truck> pTruck = static_pointer_cast<Truck>(pCar);
- // 위처럼 대입하지 않고 스스로 형변환만 하여도 상관없음.
- // 참조 카운트는 당연히 변화가 없다.
- static_pointer_cast<Car>(pCar);
- shared_ptr::get()
: 참조하고 있는 객체의 주소를 반환한다.
- shared_ptr::operator*
: 참조하고 있는 객체 자체를 반환한다.
: 즉, *(get())의 의미 - shared_ptr::operator->
: get()->의 의미가 같다.
- shared_ptr<Car> spCar( new Truck() );
- // spCar가 참조하는 객체의 주소를 반환
- Car* pCar = spCar.get();
- // spCar가 참조하는 객체의 메써드에 접근 #1
- spCar.get()->MemberFunc();
- // spCar가 참조하는 객체의 메써드에 접근 #2
- *(spCar).MemberFunc();
- // spCar가 참조하는 객체의 메써드에 접근 #3
- spCar->MemberFunc();
- #include <memory> // for shared_ptr
- #include <vector>
- using namespace std;
- class User;
- typedef shared_ptr<User> UserPtr;
- class Party
- {
- public:
- Party() {}
- ~Party() { m_MemberList.clear(); }
- public:
- void AddMember(const UserPtr& member)
- {
- m_MemberList.push_back(member);
- }
- private:
- typedef vector<UserPtr> MemberList;
- MemberList m_MemberList;
- };
- typedef shared_ptr<Party> PartyPtr;
- class User
- {
- public:
- void SetParty(const PartyPtr& party)
- {
- m_Party = party;
- }
- private:
- PartyPtr m_Party;
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- PartyPtr party(new Party);
- for (int i = 0; i < 5; i++)
- {
- // 이 user는 이 스코프 안에서 소멸되지만,
- // 아래 party->AddMember로 인해 이 스코프가 종료되어도 user의 refCount = 1
- UserPtr user(new User);
- // 아래 과정에서 순환 참조가 발생한다.
- party->AddMember(user);
- user->SetParty(party);
- }
- // 여기에서 party.reset을 수행해 보지만,
- // 5명의 파티원이 party 객체를 물고 있어 아직 refCount = 5 의 상태
- // 따라서, party가 소멸되지 못하고, party의 vector에 저장된 user 객체들 역시 소멸되지 못한다.
- party.reset();
- return 0;
- }
http://process3.blog.me/20049917212
즉, 결론만 이야기하면, 레퍼런스 카운트에 대해서만 동기화를 해서 멀티 쓰레드에서의 안정성을 얻는다.
11) 적절한 활용 예시
포인터를 담는 벡터에 대한 내용인데, 괜찮아서 링크 건다.
http://sanaigon.tistory.com/72
덧글
간단하면서도 명료하여 이해하기가 매우 쉬웠네요 ^^
TR1이 발표되기 전까지 std::auto_ptr이 C++ 'Standara' library의 유일한 스마트 포인터였다.