일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- Wireless Network
- putty
- aero glass
- Programming
- 동적 메모리 할당
- ns2
- gnuplot
- Rally
- 네트워크 시뮬레이터
- NS-2
- C
- adhoc
- malloc
- Elasticsearch
- hop
- networking
- throughput
- calloc
- C++
- trace file format
- 애드혹
- 무선통신
- TCL
- simple-wireless
- 동호대교
- awk
Archives
- Today
- Total
Pururoong
스마트 포인터 본문
C++에서는 new 연산자를 통해 클래스나 객체에 대한 메모리를 동적으로 할당할 수 있다.
할당된 메모리는 역할을 다하면 반드시 반환되어야 하며, 프로그래머가 명시해 주어야한다.
클래스의 경우, 소멸자를 통해 객체가 사라질 때, 메모리를 해제하도록 할 수 있지만,
어디까지나 클래스가 정적으로 선언된 경우에만 해당한다.
다음 예제는, 동적으로 선언된 클래스에서 소멸자가 호출되지 않음을 보여준다.
#include <iostream> class Test { public : Test() { std::cout<<"생성자 호출"<<std::endl; } ~Test() { std::cout<<"소멸자 호출"<<std::endl; } private : }; int main() { Test *t1 = new Test; //생성자만 호출 - 프로그램이 종료되어도 소멸자는 호출되지 않는다. //delete t1; return 0; }
이외에도 프로그래머는 delete를 잊거나, new와 delete의 형식을 맞추지 못하거나, delete를 두 번 사용하거나,
예외처리 구문을 통해 delete를 사용하는 등의 실수를 할 수 있다.
이런 사소한(?) 메모리 누수를 방지하기 위해 스마트 포인터를 사용할 수 있다.
[std::auto_ptr]
스마트 포인터는 스택에서 생성되어 힙 영역에 할당된 객체를 가리키고, 스코프를
벗어나면 자동으로 소멸된다.(지역 변수처럼 관리)
int main() { //std::auto_ptr을 사용하여 첫 번째 예제의 문제를 해결 Test *t1 = new Test;
std::auto_ptr<Test> p1; std::auto_ptr<Test> p2 (t1); p1 = p2; return 0; }
라인 8에서 객체의 복사가 이루어 지는데, 이 때 p2는 NULL을 가리키게 되고 메모리의 오너쉽을 p1에게 넘겨준다.
그리고 p1이 혼자서 메모리의 오너쉽을 가지고 있다가 스코프에서 벗어나게 되면 적절한 동작을 취한다.
auto_ptr은 단일 객체만 가리키도록 되어있기 때문에(delete만 호출하기 때문에) 다음과 같은 코드는 적절하지 않다.
auto_ptr<T> p1( new T ); //OK auto_ptr<T> p2( new T[n] ); //delete[]를 호출하지 않기 때문에 //메모리 헤제가 제대로 이루어지지 않는다.
또한, 자원의 소유권을 전달하는 특이한 복사 방식 때문에 STL 컨테이너의 요소로 사용할 수 없다.
아래는 COAP(Container Of Auto_Ptr)라 불리는 auto_ptr의 잘못된 사용 예제이다.
int main() { std::auto_ptr<int> p1(new int); std::vector<std::auto_ptr<int>> v; v.push_back(p1); return 0; }
<에러 메세지>
error C2558: class 'std::auto_ptr<_Ty>' : 복사 생성자를 사용할 수 없거나 복사 생성자가 'explicit'으로 선언되었습니다.
C++ 표준 위원회에서 COAP를 방지하기 위해 컨테이너의 삽입 멤버 함수의 인자로 상수 참조(const T& arg)를 받도록 정의하였는데,
auto_ptr은 소유권 이전을 하기 때문에 복사 생성자에 상수 참조를 받지 못한다고 한다.
이런 문제점들 때문에 C++11에서는 공식적으로 auto_ptr을 폐기할 예정이라고 선언하였다.
대안으로 C++11사용자는 shared_ptr과 unique_ptr을 사용할 수 있다. C++11이전 사용자는 boost libraries의
shared_ptr을 사용할 수 있다.
포인터는 스코프를 벗어나면 삭제(메모리해제)가 잘 이루어 져야하는데, 코드중에서 어떤 포인터를 복제하여 누군가 참조하고 있을
경우도 있다. 이런 문제 상황을 엘리어싱(aliasing)이라 하는데, 이 문제를 해결하려면, 포인터가 가장 마지막에 사용
되는 곳에서 delete가 이루어져야 한다. 그러나 런타임에 따라 실행순서가 바뀌는 경우에는 어디에서 메모리가 가장
마지막에 사용되는지 알아내기가 어렵다.
std::shared_ptr은 참조(Reference) 카운팅 방식으로 동작하는데, 객체의 참조를 카운트하고 있다가 포인터의
모든 오너가 포인터에 대한 참조를 마치게 되면(카운트가 0이 되면) 자동으로 실제 포인터를 delete한다.
[std::shared_ptr]
두 가지 방법으로 선언할 수 있다.
std::shared_ptr<Test> tp1(new Test);
auto tp2 = std::make_shared<Test>();
두 번째 방법에서 Test의 생성자가 파라매터를 요구하면 std::make_shared에 인자를 주면 된다.
메모리 해제시 delete만 실행되는 문제는 여전히 남아있다.
std::shared_ptr<int> p1( new int[10] ); //메모리가 제대로 해제되지 않는다. //다음과 같이 사용할 수 있다. std::vector<std::shared_ptr<int>> pv; pv.push_back(std::shared_ptr<int>(new int(4)));
혹은 boost의 shared_array를 사용할 수 있다.
boost::shared_array<int> p1(new int[10]);
Comments