STL : 컨테이너에 "auto_ptr" 객체를 넣지 말자!

왜 STL 컨테이너에 "auto_ptr" 객체를 넣으면 안될까?

C++ 표준협회에서는 STL의 요소는 반드시 복사와 할당(Copy-Constructible and Assignable)이 가능해야 한다고 명시하고 있다. 

이 훌륭한 제약은 기본적으로 하나의 객체에서 다른 객체로 할당과 복사가 일어나는 클래스가 잘 동작함을 의미한다.

특히, 다른 객체에 복사를 해도 객체의 본래 상태는 변하지 않는다.

그러나, "auto_ptr"의 경우는 이야기가 다르다. "auto_ptr" 객체를 다른 객체에 복사 또는 할당을 한다면, 원래의 객체에 변화가 발생한다. in addition to the expected changes in the copy. 좀 더 자세히 설명하면 본래의 "auto_ptr" 객체는 복사의 대상이 되는 객체에 포인터의 소유권을 넘겨주고, 원래 객체의 포인터는 NULL로 채워진다.

아래와 같은 코드를 만든다면, 무슨 일이 일어날지 생각해보자.


std::vector <auto_ptr <Foo> > vf;    /* a vector of auto_ptr's */
// ..fill vf
int g()
{
    std::auto_ptr <Foo> temp=vf[0];  /* vf[0] becomes null */
}


"temp"가 초기화 될 때, vf[0]의 포인터는 NULL이 된다. 이 포인터를 사용하게 되면, 런타임 시 문제를 일으킨다.
컨테이너로 부터 요소를 복사하려고 할 때 발생하는 경우가 될 것이다.
만약, 복사나 할당을 수행하는 어떤 코드도 없다고 해도 수 많은 알고리즘(swap(), random_shuffle 등)은 자신의 업무를 수행하기 위해 한 개 이상의 컨테이너 요소들의 일시적인 복사를 수행한다. 더구나, 어떤 컨테이너의 멤버함수 조차, 복사 작업를 한다. 즉, 컨테이너 요소들은 (의도하지 않았지만) NULL로 초기화 될 가능성이 크다. 

이러한 이유로, 추후 작업에서 이 컨테이너 요소에 대한 어떠한 접근도 안전이 보장되지 않는다.

Visual C++ 사용자들은 종종 STL 컨테이너에 "auto_ptr"를 넣어도 이제껏 아무런 문제가 발생하지 않았다고 한다.

이는 Visual C++ 의 "auto_ptr" 구현(모든 버전에 걸쳐...)이 옛날 방식이고 현재는 사용하지 않는 스펙이기 때문이다.

만약 제공회사가 현재의 "ANSI/ISO C++" 표준협회에 변경을 요구하고, 결국 그 표준 라이브러리를 변경된다면 컨테이너에 "auto_ptr"을 사용하는 코드는 분명히 심각한 오류를 야기할 것이다.

결론적으로, 컨테이너에서는 "auto_ptr"을 사용해서는 안된다.

"auto_ptr" 대신 일반적인 포인터나 잘 만들어진 스마트 포인터 클래스를 활용하는 것이 좋다.

[참고1]
정말 그런가 테스트 해 봤습니다.
아래와 같이 살짝 코드를 추가하고, 빌드했습니다.


#include <memory>
#include <vector>

std::vector<auto_ptr<int>> vecInt;

vecInt.push_back(std::auto_ptr<int>(new int(5)));

std::auto_ptr<Int> temp = vecInt[0];



어라? 컴파일 에러가 납니다.


c:\program files\microsoft visual studio 8\vc\include\vector(1125) : error C2558: class 'std::auto_ptr<_Ty>' : 복사 생성자를 사용할 수 없거나 복사 생성자가 'explicit'으로 선언되었습니다.
        with
        [
            _Ty=int
        ]
        c:\program files\microsoft visual studio 8\vc\include\vector(1117) : 클래스 템플릿 멤버 함수 'void std::vector<_Ty>::_Insert_n(std::_Vector_iterator<_Ty,_Alloc>,__w64 unsigned int,const _Ty &)'을(를) 컴파일하고 있습니다.
        with
        [
            _Ty=std::auto_ptr<int>,
            _Alloc=std::allocator<std::auto_ptr<int>>
        ]
        d:\_project\testwin32app\stlmaptest\stlmaptest\stlmaptestdlg.cpp(375) : 컴파일 중인 클래스 템플릿 인스턴스화 'std::vector<_Ty>'에 대한 참조를 확인하십시오.
        with
        [
            _Ty=std::auto_ptr<int>
        ]
STLMapTest - 오류: 1개, 경고: 9개
========== 빌드: 성공 0, 실패 1, 최신 0, 생략 0 ==========


뭔가 잘못했나, 살펴봤습니다.
아무래도 이상이 없어서, 검색을 해봤더니,

VS2005에서는 auto_ptr을 vector에 담으면 아얘 컴파일러 에러를 낸다고 합니다.
컴파일러에서 미리 오류라고 알려주는 건 고맙지만, 에러 메시지만 봐서는 내가 잘못한건지,
아닌지 절대 알 수가 없네요.
내용을 모르고 실제 프로젝트 중에 삽질을 했을 생각하니 짜증이 납니다.
알아두는게 좋을 것 같습니다. ^^


출처 : http://www.devx.com/cplus/Article/16328/0/page/6
번역 : 너굴너굴

by 너굴너굴 | 2009/03/24 00:24 | nUgURi_GURU | 트랙백 | 덧글(2)

트랙백 주소 : http://nuguri.egloos.com/tb/4889691
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented at 2009/07/27 19:26
비공개 덧글입니다.
Commented by 너굴너굴 at 2009/08/06 13:44
explicit 에러는 그부분이 아니라 이미, 변수 선언에서 난 것 인데요.

"std::vector<std::auto_ptr<int>> vecInt;" 이 부분이네요.

이 부분을 컴파일 가능하게 할 수 있을까요?

문법에 오류가 없어 보입니다.

제가 sj님의 글을 잘못 이해한건가요? 댓글의 의도는 잘 모르겠네요.

더구나, "책을 제대로 읽지 않았다" 말과 "풋"의 의미는 도통....

그리고, 컴파일 해보지 않고 자신감을 갖는 건 굉장히 위험한 행동이라고 생각합니다.

학생이시던, 현업에 종사하시건 상관없이, 컴파일 하고 얘기하시는게, 우스운 꼴 안당하는 길이라 생각합니다.

제 글에 잘못이 있으면 수정하겠습니다.

정확히 어떤 부분이 잘못 되었는지 알려주시기 바랍니다.

마지막으로 정확히 말하고자 하는 내용이 어떤 것이며 그 내용이 어느 책에 나오는지 또한 알려주시면 꼭 사서 참고하겠습니다.

수고하세요 ^^

:         :

:

비공개 덧글

◀ 이전 페이지다음 페이지 ▶