티스토리 뷰

728x90

자원 관리에는 객체가 그만!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//여러 형태의 투자를 모델링한 클래스 계통의 최상위 클래스
class Investment { . . . };   
 
/*Investment  클래스 계통에 속한 클래스의 객체를
  동적 할당하고 그 포인터를 반환합니다.
  이 객체의 해제는 호출자 쪽에서 직접 해야 합니다.*/
Investment* createInvestment();
 
void f()
{
    //팩토리 함수를 호출합니다.
    Investment *pInv = createInvestment();   
    
    // pInv를 사용합니다.     
    // TODO    
    
    // 객체를 해제합니다.                                 
    delete pInv;                                            
}
 
cs

1. ( . . . )부분 어딘가에서 return문(도중하차)이 있을 가능성이 있습니다.
2. Continue 혹은 goto 문에 의해 갑작스레 루프로부터 빠져나올 가능성이 있습니다.
3. ( . . . )부분의 어떤 문장에서 예외를 던질 가능성이 있습니다.
4. 객체를 담고 있는 메모리가 누출되고, 그와 동시에 그 객체가 갖고 있던 자원까지 모두 샙니다.

 

해결방법1

자원을 객체에 넣고 그 자원 해제를 소멸자가 맡도록 하며,
실행 제어가 f를 떠날 때 C++가 자동으로 호출해 주는 소멸자에 의해 해당 자원을 저절로 해제 할 수 있습니다.

ex 1> auto_ptr : 포인터와 비슷하게 동작하는 객체[스마트 포인터(smart pointer)]로서, 가리키고 있는 대상에 대해 소멸자가 자동으로 delete를 불러주도록 설계

1
2
3
4
5
6
7
void f()
{
    //팩토리 함수를 호출합니다.
    std::auto_ptr<Investment> pInv ( createInvestment( ) );            
    // 예전처럼 pInv를 사용합니다.
    // auto_ptr의 소멸자를 통해 자동으로 소멸
}                                                                              
cs


//pInv를 삭제합니다.

※자원 관리에 객체를 사용하는 방법의 특징!!
1. 자원을 획득한 후에 자원 관리 객체에게 넘깁니다. ( 자원 획득 즉 초기화( RAII ) )
2. 자원 관리 객체는 자신의 소멸자를 사용해서 자원이 확실히 해제되도록 합니다.


auto_ptr은 자신이 소멸될 때 자신이 가리키고 있는 대상에 대해 자동으로 delete를 먹기 때문에, 어떤 객체를 가리키는 auto_ptr의 개수가 둘 이상이면 안된다. 개체를 복사하면 원본 객체는 null로 만든다. 복사하는 객체만이 그 자원의 유일한 소유권을 갖는다.

std::auto_ptr pInv1( createInvestment ( ) ); 

//pInv1 = createInvestment함수에서 반환된 객체
std::auto_ptrpInv2( pInv1 );   //pInv2 = 객체, pInv1 = null
pInv1 = pInv2;  //pInv1 = 객체, pInv2 = null

 

해결방법2

shared_ptr : 
참조 카운팅 방식 스마트 포인터( RCSP ), 특정한 어떤 자원을 가리키는(참조하는) 외부 객체의 개수를 유지하고 있다가 그 개수가 0이 되면 해당 자원을 자동으로 삭제하는 스마트 포인터

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
 
void f()
 
{
    // pInv1 =  객체
    std::tr1::shared_ptr<Investment> pInv1( createInvestment( ) );   
    
    // pInv1 = pInv2 = 객체
    std::tr1::shared_ptr<Investment>pInv2( pInv1 );                             
 
    //pInv1 = pInv2 = 객체
    pInv1 = pInv2;                                                                         
 
     // pInv1 및 pInv2는 소멸되며, 이들을 가리키고 있는 객체도 자동 삭제 됩니다.
}
   
cs

잘못된 사용

1
2
3
4
5
6
std::auto_ptr<std::string>aps(new std::string[10]);
std::tr1::shared_ptr<int> spi( new int[1024] );
 
 
 
 
cs

std::auto_ptr 및 tr1::shared_ptr은 소멸자 내부에서 delete [ ]가 ‘아닌’ delete 연산자를 사용하기 때문입니다. 컴파일에러가 발생하지 않습니다.

C++표준 라이브러리에서는 동적 할당된 배열을 위해 준비된 std::auto_ptr 혹은 std::tr1::shared_ptr 같은 클래스가 제공되지 않습니다. 
이는 string 및 vector로 거의 대체할 수 있기 때문입니다. 

자원을 관리하는 객체를 써서 자원을 관리하는 것이 중요!!!!!!!

 

결론

자원 누출을 막기 위해, 생성자 안에서 자원을 획득하고 소멸자에서 그것을 해제하는  RAII객체를 사용합시다.
일반적으로 널리 쓰이는 RAII 클래스는 std::auto_ptr 그리고 std::tr1::shared_ptr 입니다.

이 둘 가운데 std::tr1::shared_ptr이 복사 시의 동작이 직관적이기 때문에 상용함이 편리 합니다.

반면, auto_ptr은 복사되는 객체(원본 객체)를 NULL로 만들어 버립니다.

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/11   »
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
글 보관함
250x250