본문 바로가기

C++ Language/Tip / Information

auto_ptr 키워드

프로그래밍을 하다가 보면


포인터변수를 이용하여 힙영역에 메모리를 할당을 받아서


작업을 하는 경우가 많이 있습니다.


이럴 경우 작업을 다 한후에 메모리에서 할당 받은 부분을


해제 시켜 주어야 되는데,


잊어버리고 해제를 안하는 경우도 있고,


해제를 하는 코드를 작성하였지만, 그 이전에 어떤 예외로


인하여 해제 코드까지 못가는 경우도 있습니다.


이럴 경우 가장 간단한 방법으로 auto_ptr 키워드를 사용하게 됩니다.


auto_ptr 키워드는 c++ 표준 라이브러리로, memory 파일에 존재하고,


하는 역할은 기본적으로 포인터가 하는 역할을 그대로 수행을 하고,


거기에 다가 프로그래머가 delete 함수를 사용하지 않아도


생성된 객체가 종료되는 시점에 자동으로 메모리 할당이 해제 됩니다.


즉, 프로그래머가 따로 delete 함수로 메모리 할당 해제를 시켜 주지 않아도


됩니다.


먼저 auto_ptr 클래스를 보면,


template
	class auto_ptr {
public:
	typedef _Ty element_type;
	explicit auto_ptr(_Ty *_P = 0) _THROW0()
		: _Owns(_P != 0), _Ptr(_P) {}
	auto_ptr(const auto_ptr<_Ty>& _Y) _THROW0()
		: _Owns(_Y._Owns), _Ptr(_Y.release()) {}
	auto_ptr<_Ty>& operator=(const auto_ptr<_Ty>& _Y) _THROW0()
		{if (this != &_Y)
			{if (_Ptr != _Y.get())
				{if (_Owns)
					delete _Ptr;
				_Owns = _Y._Owns; }
			else if (_Y._Owns)
				_Owns = true;
			_Ptr = _Y.release(); }
		return (*this); }
	~auto_ptr()
		{if (_Owns)
			delete _Ptr; }
	_Ty& operator*() const _THROW0()
		{return (*get()); }
	_Ty *operator->() const _THROW0()
		{return (get()); }
	_Ty *get() const _THROW0()
		{return (_Ptr); }
	_Ty *release() const _THROW0()
		{((auto_ptr<_Ty> *)this)->_Owns = false;
		return (_Ptr); }
private:
	bool _Owns;
	_Ty *_Ptr;
	};


이렇게 구성이 되어 있습니다.

여기에서 보게 되면,


생성자함수와 복사생성자함수, 복사대입생성자 함수가 있고,

연산자 함수로 *, -> 함수가 재정의 되어 있으며,


get, release 함수를 정의 해 놓았습니다.


get 함수 같은 경우는 객체가 가지고 있는 주소 값을 출력 시키는 함수이며,

release 함수는 가지고 있는 주고 값을 삭제 시키는 함수 입니다.


기본사용형태는


auto_ptr<type>으로 사용하시면 됩니다.


예로 보면,

auto_ptr<int>, auto_ptr<char> 이런식으로 사용하면 됩니다.


간단한 예시 소스를 보게 되면,


#include
#include

using namespace std;

int main()
{
	auto_ptr auto_ptr_value(new int);

	return 0;
}

이런식으로 사용이 됩니다.


하지만 메모리 할당을 위 소스대로 시키지 않고,


먼저 객체를 생성하고, 그 후에 메모리 할당을 받기 위해


소스를 작성할 경우에


auto_ptr_value = new int;


이런식으로 작성 할 경우에는


error C2679: binary '=' : no operator defined which takes a right-hand operand of type 'int *' (or there is no acceptable conversion)


이런 메세지의 에러가 뜨게 됩니다.


이는


오른쪽 피연산자로 'int *' 형식을 사용하는 연산자가 없거나 허용되는 변환이 없습니다.


라는 뜻으로, 실제적으로 포인터를 사용하여 객체를 생성한 경우가 아니기 때문에


생기는 에러 메세지로,


밑의 소스처럼 명시적으로 자료형을 나타내 주어야 합니다.


#include
#include

using namespace std;

int main()
{
	auto_ptr auto_ptr_value;
	auto_ptr_value = static_cast< auto_ptr >(new int);

	return 0;
}


이런식으로 코드를 작성하게 되면,


에러 없이 잘 동작이 됩니다.


이제 auto_ptr 키워드에서 사용하면 안되는 경우를 보면,


#include
#include

using namespace std;

int main()
{
	auto_ptr auto_ptr_value(new int[10]);
	auto_ptr_value[0] = 1;
	*(auto_ptr_value+2) = 3;

	return 0;
}

위의 auto_ptr 클래스에서 소멸자 함수를 보게 되면,

delete 함수가 있는데, 이는 배열할당을 해제 시키는 것이 아닌


일반 메모리 할당만을 해제 시키는 것입니다.


즉, 메모리 할당을 할 때 배열로 할당 시키면 안된다는 것입니다.


그래서 []을 사용한 입력이 되지 않는 것입니다.


#include
#include

using namespace std;

int main()
{
	int value = 5;
	auto_ptr auto_ptr_value(&value);

	return 0;
}

이 경우는 auto_ptr 키워드에서 new 함수를 사용하여 메모리 할당을


직접 시켜 주어야만 합니다.


만약 위 소스처럼 먼저 생성된 변수의 주소를 가지게 되면,


소멸자의 delete 함수 때문에 실행 에러가 나게 됩니다.


#include
#include

using namespace std;

int main()
{
	auto_ptr auto_ptr_value(new int);
	auto_ptr auto_ptr_value2(auto_ptr_value);

	return 0;
}

위 소스에서 auto_ptr로 생성한 객체를


다음에 auto_ptr로 생성한 객체에 입력 값으로 넣는 것으로


복사생성자를 이용하는 방법으로 나타내었는데


auto_ptr_value와 auto_ptr_value2 모두 auto_ptr_value에서 생성한


메모리를 가르키게 됩니다.


이 상태에서 종료를 시키게 되면, 두 번 delete를 호출 하게 되어,


문제가 생길 것 같지만,


auto_ptr 클래스에서 보면, 맴버 변수에 부울함수로 만들어진 하나의 변수가


있는데 이를 이용하여, 문제를 없애도록 합니다.


즉, auto_ptr_value 객체에서 메모리 할당을 하였을 때 auto_ptr_value 객체의


부울형 맴버변수를 1로 두고 있다가, auto_ptr_value2 객체에서 auto_ptr_value로


복사 생성을 할 때 auto_ptr_value 객체의 부울형 맴버변수를 0으로 바꾸고


auto_ptr_value2 객체의 부울형 맴버변수를 1로 두도록 하여 소멸할 때 소멸자에서


부울형 멤버변수 1을 가지고 있을 경우에만 delete함수를 부르도록 한 것입니다.


즉, 하나의 소유권 같은 것을 만들어 여러 객체가 같은 주소를 가지고 있더라도,


한 객체만 delete 함수를 부를 수 있도록 하였습니다.


#include
#include

using namespace std;

int main()
{
	auto_ptr auto_ptr_value(new int);
	auto_ptr auto_ptr_value2(new int);

	auto_ptr_value2 = auto_ptr_value;

	return 0;
}

이 소스는 복사대입 연산자를 보는 것인데,


auto_ptr_value2 객체에 auto_ptr_value 객체를 입력시키도록 합니다.


그렇게 되면, auto_ptr_value2 객체의 주소는 자동적으로 auto_ptr 클래스에서


delete 함수를 부르게 되어 메모리 할당을 해제 시킨 후 auto_ptr_value 객체의


주소 값을 가지게 됩니다.


'C++ Language > Tip / Information' 카테고리의 다른 글

클래스에서의 초기화(initialization)와 대입(assignment)  (0) 2010.02.16
8진수 / 10진수 / 16진수 출력하기  (0) 2010.02.16
const_cast 키워드  (0) 2010.02.12
mutable 키워드  (0) 2010.02.12
상수함수란?!  (0) 2010.02.12