본문 바로가기
C C++ - STL

STL - 12 auto_ptr

by violetoz 2014. 2. 13.

출처 카페 > The C++ Program.. | 라온
원문 http://cafe.naver.com/cppstl/439

오랜만에 강좌를 올립니다... ^^

 

Standard Library에서 제공하는 Smart pointer의 한 종류인

auto_ptr에 대한 사용법과 주의 할 점을 다루고자합니다.

여러가지 관점에서 smart pointer는 만들어지고 사용되고 있습니다.

Smart Pointer에 대한 내용은

http://en.wikipedia.org/wiki/Smart_pointer

http://www.boost.org/libs/smart_ptr/smart_ptr.htm 참고하세요.

 

auto_ptr은 단 한 가지 문제에 대해서만 효과가 있는 Smart pointer의 한 종류입니다.

그러므로 사용 방법을 정확히 알아야 합니다. 한 가지 문제라는 부분은 memory leak 방지를 위한

자동 소멸에 대한 부분입니다. 우선 일반적인 Pointer 예를 보고 auto_ptr에 대하여 살펴보도록 합시다.

 

예제 1.

void function()
{
    AClass *p = new AClass;
    ...
    delete p;
}

 

흔히 예외에 대하여 생각하지 않는 예제를 만들거나 초보자가 하는 형태는 pointer를 선언하고

new를 이용하여 명시적으로 객체를 생성하고, delete를 이용하여 객체를 제거합니다.

그리고, 보다 심각한 경우가 p 를 return 할 경우 인데, 어떤 경우든 

실행도중 예외가 발생하면 delete가 실행 되지 않아 memory leak이 발생하게 됩니다.

이를 방지하려면 모든 예외를 방지 해야하는데, 코드가 복잡해 지는 문제가 생깁니다.

 

예제 2.

void function()
{
    AClass *p = new AClass;

    try{
        ...
    }
    catch ( const std::exception& error ){
        delete p;
        throw;
    }
    catch (...){
        delete p;
        throw;
    }

    delete p;
}

 

이런 경우 필요한 것이 Smart Pointer인데 C++ Standard Library의 auto_ptr 를 살펴 보겠습니다.

 

예제 3.

#include <memory>

void function()
{
    std::auto_ptr<AClass> p( new AClass );

    ...
}

 

더 이상 delete나 catch는 필요하지 않습니다. 예외를 일으켜도 문제 될 것이 없어집니다.

 

auto_ptr<> 은 -> 로 클래스나 구조체의 멤버를 이용하고 , * 로 역참조 할 수 있습니다.

하지만 = 을 이용해서 초기화 할 수 없습니다. 그러니까.

auto_ptr<AClass> p( new AClass );  이런 형태로 초기화 하지만

auto_ptr<AClass> p = new AClass;   이것은 에러 입니다.

말그대로 명시적 선언으로만  초기화가 된다는 것입니다. ( 명시적 explicit, 묵시적 implicit 선언은 가장 아래.)

 

auto_ptr<> 사용에 주의할 점이 있습니다. 아래 사항은 반드시 숙지해 두고 사용하기 바랍니다.

1. 소유권 공유 할 수 없습니다. (auto_ptrs cannot share ownership.)

2. 배열 타입은 지원하지 않습니다. (auto_ptrs are not provided for arrays.)

3. 범용 스마트 포인터가 아닙니다. (auto_ptrs are not "universal smart pointers.")

4. STL container의 요소로 사용하면 안됩니다. (auto_ptrs don't meet the requirements for container elements.)

 

소유권 이전 부분을 좀 여러가지 관점에서 봐야하는데 우선 간단하게,

auto_ptr<AClass> p1 ( new AClass );

auto_ptr<AClass> p2 ( p1 );

이렇게 하면 p1은 NULL이 되고 p2는 p1이 가지고 있던 객체를 가지게 됩니다.

일반적인 포인터에서 p1과 p2는 같은 객체를 지정하게 됩니다. ( AClass *p1 = new AClass; AClass *p2; p2 = p1; )

이러한 것 여러가지 문제를 일으키게 됩니다.

 

auto_ptr의 좋은 예는 exceptional c++의 강경한 예외 안정성(strong exception safety)을 지킬 수 있는

code 예가 좋을 것 같습니다.

 

아래 code에서 예외가 발생할 수 있는 곳은 몇 군데 일까요....?

std::string EvaluateSalaryAndReturnName( Employee e ) 
{
    if( e.Title() == "CEO" || e.Salary() > 100000 ){
        std::cout << e.First() << " " << e.Last() << " is overpaid" << endl;
    }
    return e.First() + " " + e.Last();
}

 

23 곳입니다. 제가 찾은건 20개 였었는데, 내용을 보니 이해가 되더군요. 어쨌든 아래 예가 strong exception safety를

고려한 code 입니다.

 

std::auto_ptr<std::string> EvaluateSalaryAndReturnName( Employee e )
{
    std::auto_ptr<std::string> result
      = new std::string( e.First() + " " + e.Last() );

    if( e.Title() == "CEO" || e.Salary() > 100000 ){
        std::string message = (*result) + " is overpaid\n";
        std::cout << message;
    }

    return result;
}

 

마지막으로 잊지 말아야 할 것은 소유권을 넘지지 않을 경우 그러니까 함수의 parameter나 argurment로

사용할 때 반드시 const로 하여야 합니다. 그러니까.

void function( const std::auto_ptr<ValueType> &p )

와 같이 const를 사용하여야 합니다. 그렇지 않으면 소유권이 넘어가 버리기 때문에 문제가 생기는건 당연한 것이죠.

 

오늘은 여기 까지 입니다. 설명이 부족한 부분은 덧글 질문해 주시기 바랍니다.

 

참고 explicit, implicit conversion

[

    AClass a

    BClass b(a) explicit conversion

 

    AClass a;

    BClass b = a; implicit conversion

]