참고 : 포인터 실무 KIN
※ 부스트 라이브러리 설치 (Boost library)
1. Visual Studio 2005 / 2008
: 도구(tool) - 옵션(option) - 프로젝트(projects) - VC++ 디렉토리(VC++ directories) 선택
- 다음 파일의 디렉토리 표시 (Show directories for)
- 콤보박스에서 포함 파일(include files)에 boost library를 설치한 경로를 추가!
2. Borland C++ Compiler / C++ Builder X
: bcc.exe가 위치하는 폴더 안에 bcc32.cfg 파일을 열어서 boost library를 설치한 디렉토리 경로를 추가!
(ex) -I"C:\development\bcc\include;C:\boost 디렉토리"
-L"C:\development\bcc\lib;C:\boost 디렉토리"
3. GNU C++ Compiler
: 환경변수 CPLUS_INCLUDE_PATH에 boost library를 설치한 디렉토리 경로를 추가!
==================================================================================================
1. auto_ptr
: 소유권 독점 방식으로 구동되는 스마트 포인터. 복사시 소유권 이전 되는 소유권 독점 방식을 취함.
: C++ 표준 라이브러리에서 제공
: 소유권 이전 금지 - const 키워드 사용 (ex) const boost::auto_ptr<MyClass> ptq(new MyClass);
[특징]
- 자동으로 포인터에 할당된 메모리를 해제한다.
- 자동으로 포인터를 초기화한다. (디폴트 생성자)
- 댕글링 포인터 문제를 해결한다.
[주의사항]
- auto_ptr은 STL 컨테이너(vector, list, map, hashtable 등)와 사용할 수 없다.
- auto_ptr은 동적 배열에는 사용할 수 없다.
- auto_ptr은 힙영역에 동적으로 할당된 메모리에만 적용 가능하다.
--------------------------------------------------------------------------------------------------
[예제]
--------------------------------------------------------------------------------------------------
#include <iostream>
#include <memory>
#include <boost/shared_ptr.hpp>
using namespace std;
class Car
{
public:
Car();
~Car();
void race();
};
Car::Car()
{
cout << "생성자" << endl;
}
Car::~Car()
{
cout << "소멸자" << endl;
}
void Car::race()
{
cout << "붕붕~!" << endl;
}
boost::shared_ptr<Car> createObject()
{
return boost::shared_ptr<Car>(new Car());
}
int main(void)
{
boost::shared_ptr<Car> a;
boost::shared_ptr<Car> b;
a = createObject();
b = a;
b->race();
if(a.get() != NULL) // 실행되지 않는다. 소유권 이전 후 a는 NULL이 된다.
a->race();
return 0;
}
==================================================================================================
2. shared_ptr
: 소유권이 공유되는 방식으로 동작하는 스마트 포인터
: 동일한 객체를 가리키는 스마트 포인터의 개수를 센 후, 이 개수가 0이 될 때 객체를 삭제한다.
즉, 동일한 객체를 참조하는 모든 스마트 포인터가 자신의 scope를 벗어날 때 공유 객체의 소멸이
결정되는 방식.
: STL 컨테이너에서 사용이 가능하다. (boost library를 반드시 설치하고, include 해야 한다.)
[주요 특징]
: 강한 참조의 성격을 가지고 있다.
: 쓰레드에 안전하게 설계되어 있다. (그러나 쓰레드의 실행 순서에 따라 영향은 받으므로 설계가 중요!)
: Thread Safety 해제 - 헤더 파일에 " #define BOOST_DISABLE_THREADS "를 적어준다.
[주의사항]
- 순환참조를 하면 안된다. (정확히 참조 카운트를 알 수 없기 떄문)
- 이름이 없는 shared_ptr을 사용을 피하는 것이 좋다.
(이미 동적 할당되어 생성된 객체가 삭제되지 않아서 메모리릭이 발생할 수 있기 때문이다.)
- 스마트 포인터 생성시, 생성자를 직접 호출하거나 명시적 형변환만 가능하다.
(암시적 형변환은 지원하지 않는다.)
- 원본 포인터(raw pointer)를 직접 삭제 할 수 없다. (reset(), 재할당 혹은 스마트 포인터가 파괴 될 때
자동으로 원본 포인터가 삭제되도록 작성하는 것이 좋다.)
--------------------------------------------------------------------------------------------------
[예제1]
#include <string>
#include <iostream>
#include <memory>
#include <vector>
#include <boost/shared_ptr.hpp> // shared_ptr을 사용하기 위해서는 반드시 추가해야 한다.
using namespace std;
class Fruit
{
public:
Fruit(string name);
~Fruit();
string getName();
private:
string name;
};
Fruit::Fruit(string name)
{
this->name = name;
cout << this->name + " 생성됨" << endl;
}
Fruit::~Fruit()
{
cout << this->name + " 소멸됨" << endl;
}
string Fruit::getName()
{
return name;
}
int main(void)
{
typedef boost::shared_ptr<Fruit> fruit_sPtr; // 참조 카운팅 방식의 스마트 포인터
vector<fruit_sPtr> vec;
fruit_sPtr s = fruit_sPtr(new Fruit("Apple"));
vec.push_back(fruit_sPtr(new Fruit("pear")));
vec.push_back(fruit_sPtr(new Fruit("banana")));
vec.push_back(fruit_sPtr(new Fruit("kiwi")));
vec.push_back(s);
cout << (*s).getName() << endl;
return 0;
}
--------------------------------------------------------------------------------------------------
[예제 2]
#include <iostream>
#include <string>
#include <memory>
#include <boost/shared_ptr.hpp>
using namespace std;
class Shape
{
public :
Shape() {}
~Shape() {}
void draw(string str);
};
void Shape::draw(string str)
{
cout << str.c_str() << endl;
}
int main(void)
{
typedef boost::shared_ptr<Shape> ShapePtr;
Shape* shape1 = new Shape();
ShapePtr sptr1(shape1);
sptr1.get()->draw("Circle");
cout << sptr1.use_count() << endl; // use_count() : 참조 카운트를 반환한다.
ShapePtr sptr2 = sptr1;
cout << sptr1.use_count() << endl;
sptr1.reset();
cout << sptr2.use_count() << endl;
return 0;
}
==================================================================================================
3. weak_ptr
: shared_ptr에서 순환참조로 발생하는 문제를 해결하기 위해서 사용하는 스마트 포인터
: shared_ptr과는 달리 객체에 대한 소유권을 가지지 않고 객체를 사용한다.
: 약한 참조의 성질을 가지고 있다.
(객체가 살아있도록 유지시키지 않고, 단순히 객체가 살아 있는 동안 참조)
: 자신이 가리키는 객체가 실제로 살아있는지 체크할 수 없으므로, 댕글링 포인터가 될 수 있다.(단점)
(따라서 lock 함수를 사용해서 shared_ptr을 얻어올 때 반드시 리턴값이 NULL(0)인지 체크해야 한다.)
--------------------------------------------------------------------------------------------------
[예제]
#include <iostream>
#include <memory>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
using namespace std;
class Parent;
class Child;
typedef boost::shared_ptr<Parent> parentSPtr;
typedef boost::weak_ptr<Parent> parentWPtr;
typedef boost::shared_ptr<Child> childSPtr;
class Parent
{
public:
Parent() { cout << "Parents 생성" << endl; };
~Parent() { cout << "Parents 소멸" << endl; };
void drink() { cout << "맥주를 마신다." << endl; };
childSPtr kid;
};
class Child
{
public:
Child() { cout << "Child 생성" << endl; };
~Child() { cout << "Child 소멸" << endl; };
void drink();
parentWPtr father;
};
void Child::drink()
{
cout << "우유를 마신다." << endl;
parentSPtr f = father.lock(); // shared_ptr을 얻는다.
if(f) // 객체가 존재하는지 반드시 체크해야 한다.
f->drink();
}
int main(void)
{
Child* child = new Child();
parentSPtr pSptr(new Parent);
childSPtr cSptr(child);
cout << "#parent의 참조개수: " << pSptr.use_count() << endl;
cout << "#child의 참조개수: " << cSptr.use_count() << endl;
pSptr->kid = cSptr;
cSptr->father = pSptr;
cout << "#parent의 참조개수: " << pSptr.use_count() << endl;
cout << "#child의 참조개수: " << cSptr.use_count() << endl;
cSptr->drink();
pSptr.reset();
return 0;
}
==================================================================================================
4. intrusive_ptr
: 참조 개수를 스마트 포인터 안에 두지 않고, 관리할 클래스 안에 보관하는 방식의 스마트 포인터
: intrusive_ptr은 shared_ptr과 마찬가지로 참조 카운팅 방식으로 객체의 소멸 시점을 결정한다.
하지만 intrusive_ptr의 경우 관리될 객체가 스스로 자신의 내부에 참조개수를 유지, 관리하도록
요구한다.
: intrusive_ptr 인스턴스가 새롭게 생성될 때는 intrusive_ptr_add_ref() 함수를 자동으로 호출하여
참조의 개수를 증가시키도록 요구하고, 반대로 intrusive_ptr 인스턴스가 삭제 때
intrusive_ptr_release() 함수를 호출하여, 참조개수가 0일 될 때, 객체를 삭제하도록 요청한다.
( intrusive_ptr_add_ref()와 intrusive_ptr_release() 함수의 경우 사용자가 직접 구현해야 하며,
이 때 함수의 인자로 객체의 포인터를 넘겨줍니다. )
: intrusive_ptr은 암묵적 형변환을 허용한다.
[사용해야 하는 이유]
- 기존의 독자적으로 참조개수를 가지는 객체에 스마트 포인터를 적용하기 위해서 필요
- shared_ptr에 비해 작은 메모리 공간을 차지.
(일반 포인터와 마찬가지로 포인터(T*) 형태로 대입 가능!)
--------------------------------------------------------------------------------------------------
[예제]
[ intrusivePtrTest.h ]
#include <iostream>
#include <memory>
#include <vector>
#include <boost/intrusive_ptr.hpp>
#include <boost/shared_ptr.hpp>
using namespace std;
class SharedObject
{
public:
SharedObject() : ref_count(0) { cout << "생성됨" << endl; };
~SharedObject() { cout << "소멸됨" << endl; };
void Hello();
int AddRef();
int Release();
private:
int ref_count;
};
void intrusive_ptr_add_ref(SharedObject* ptr);
void intrusive_ptr_release(SharedObject* ptr);
[ intrusivePtrTest.cpp ]
#include "intrusivePtrTest.h"
void SharedObject::Hello()
{
cout << "Hello!" << endl;
}
int SharedObject::AddRef()
{
// 참조 카운팅 증가시 SharedObject 안에 있는 ref_count 변수를 증가한다.
return ++ref_count; // 반환
}
int SharedObject::Release()
{
// 참조 카운팅 감소시 SharedObject 안에 있는 ref_count 변수를 감소한다.
if(--ref_count == 0) // 참조 카운팅이 0 이면
delete this; // 객체 소멸
return ref_count; // 참조 카운팅이 0보다 크다면 반환
}
int main(void)
{
typedef boost::intrusive_ptr<SharedObject> iPtr;
iPtr p = new SharedObject();
vector<iPtr> vec;
vec.push_back(iPtr(new SharedObject));
vec.push_back(iPtr(new SharedObject));
vec.push_back(iPtr(new SharedObject));
vec.push_back(p);
p->Hello();
return 0;
}
void intrusive_ptr_add_ref(SharedObject* ptr) // intrusive_ptr이 생성될 경우
{
ptr->AddRef();
}
void intrusive_ptr_release(SharedObject* ptr) // intrusive_ptr이 소멸될 경우
{
ptr->Release();
}
==================================================================================================
5. shared_array
: 동적 배열 포인터를 보관, 유지하는 스마트 포인터
: 기능면에서는 shared_ptr과 유사 (배열에 대해 동작)
: 배열처럼 처리 가능
--------------------------------------------------------------------------------------------------
[예제]
[ SharedArrayTest.h ]
#include <iostream>
#include <memory>
#include <boost/shared_array.hpp>
using std::cout;
using std::endl;
class Sample
{
public:
Sample() { cout << "생성" << endl; }
~Sample() { cout << "소멸" << endl; }
void print() { cout << "print" << endl; }
};
[ SharedArrayTest.cpp ]
#include "SharedArrayTest.h"
int main(void)
{
boost::shared_array<Sample> samplePtr(new Sample[5]); // 동적으로 할당된 배열일 경우 사용
samplePtr[2].print(); // 배열처럼 사용이 가능하다.
return 0;
}
==================================================================================================
6. scoped_ptr
: 동적으로 할당된 객체의 포인터를 가지며, 유효범위를 벗어나 자신이 삭제 될 때,
가리키는 객체를 자동으로 삭제하는 스마트 포인터 (가리키는 객체에 대한 삭제를 자동으로 수행)
: auto_ptr과 달리 가지는 포인터를 다른 변수에 복사하거나 할당할 수 없으며,
소유권 역시 이전할 수 없다.
: STL의 컨테이너의 항목으로는 사용할 수 없다는 약점이 있다. → shared_ptr을 사용하는 것이 좋다.
: scoped_array : scoped_ptr과 유사. 동적으로 생성한 객체 배열을 사용할 때 사용!
--------------------------------------------------------------------------------------------------
[예제]
[ ScopedPtrTest.h ]
#include <iostream>
#include <memory>
#include <boost/scoped_ptr.hpp>
using std::cout;
using std::endl;
class Sample
{
public:
Sample() { cout << "생성" << endl; }
~Sample() { cout << "소멸" << endl; }
void print() { cout << "print" << endl; }
};
[ ScopedPtrTest.cpp ]
#include "ScopedPtrTest.h"
typedef boost::scoped_ptr<Sample> scopePtr;
void printStr(scopePtr* Ptr); // 값 복사가 불가능하므로 포인터 형태로 넘겨야 한다.
int main(void)
{
scopePtr p1(new Sample());
scopePtr p2(new Sample());
p1->print();
printStr(&p1); // 스마트 포인터 scoped_ptr(scopePtr)의 포인터를 넘긴다.
/*
// scoped_ptr - 자신이 가지는 포인터를 다른 인스턴스로 할당하거나 넘겨줄 수 없다.
// 한번 가리키는 객체에 대한 삭제의 책임을 전적으로 진다.
// (복사가 빈번한 STL에서 사용할 수 없다.)
p2 = p1 // 에러! 할당 불가!
scopePtr p3(p1) // 에러!
*/
return 0;
}
void printStr(scopePtr* Ptr) // 값 복사가 불가능하므로 call by reference(address)로 인자를 넘긴다.
{
(*Ptr)->print();
}
==================================================================================================
'IT_Programming > C · C++' 카테고리의 다른 글
[C] C언어에서 inline assembly 사용하기 (0) | 2009.10.07 |
---|---|
[펌] MySQL 최적화 c api 소스 (0) | 2009.09.16 |
[펌_C++] SAFE_DELETE 를 template으로 구현! (0) | 2009.08.12 |
[펌_Win32 C++] Configuration MS SQL Express, ODBC DSN with Win32 C++ (0) | 2009.08.06 |
[C] 해당경로의 파일만 출력하기 / 하위 디렉토리도 검사 (0) | 2009.07.01 |