Smart Pointers

Introduction
Common Requirements
Exception Safety
Exception-specifications
History and Acknowledgements
References

Introduction

스마트 포인터는 동적으로 할당할 수 있는(heap상의) 오브젝트의 포인터를 보관 유지하는 오브젝트이다.  이것들은 가리켜진 오브젝트를 적당한 타이밍에 자동적으로 삭제하는 일을 제외하면 C++ auto_ptr 포인터와 같이 행동한다. 스마트 포인터는 동적으로 할당할 수 있는 오브젝트를 예외가 발생해도 확실히 파기하고 싶은 것 같은 때에 특별히 도움이 된다. 그리고 복수의 소유자에게 공유되고 있는 동적으로 할당할 수 있었던 오브젝트를 관리하는데도 사용할 수 있다.

개념적으로는 스마트 포인터는 가리켜진 오브젝트를 소유하고 있는 것처럼 보인다. 그리고 오브젝트가 이미 필요 없게 되었을 때 책임을 가지고 삭제한다.

스마트 포인터 라이브러리는5종류의 스마트 포인터의 클래스 템플릿을 제공한다:

scoped_ptr

<boost/scoped_ptr.hpp>

오브젝트의 소유권을 독점하는 단순한 스마트 포인터. 복사 불가.

scoped_array

<boost/scoped_array.hpp>

배열을 독점적으로 소유하는 단순한 스마트 포인터. 복사 불가.

shared_ptr

<boost/shared_ptr.hpp>

복수의 포인터로 오브젝트의 소유권을 공유하는 스마트 포인터.

shared_array

<boost/shared_array.hpp>

복수의 포인터로 배열의 소유권을 공유하는 스마트 포인터.

weak_ptr

<boost/weak_ptr.hpp>

shared_ptr가 소유하는 오브젝트를 소유하지 않고 액세스 하는 스마트 포인터.

intrusive_ptr

<boost/intrusive_ptr.hpp>

파묻힌 참조 카운트에 의해 소유권을 공유하는 스마트 포인터.

이러한 템플릿은 std::auto_ptr 템플릿을 보완하도록 설계되고 있다.

이것들은 " Resource Acquisition Is Initialization " 이데엄(역주:RAII이데엄 「자원 획득을 초기화 시에 실시한다」 것에 따라 오브젝트의 소유권의 소재를 명확하게 하는)의 전형적인 예이다. 이 이데엄은 Bjarne Stroustrup "The C++ Programming Language" 3 14.4 장 자원 관리의 항에서 진술되고 있다.

테스트 프로그램 smart_ptr_test.cpp 가 스마트 포인터의 동작 확인을 위해서 제공되고 있다.

Boost smart pointer 라이브러리의 낡은 버전에 대한 페이지 compatibility  이전 버전의 스마트 포인터의 구현으로부터의 변경에 대해 말하고 있다.

smart pointer timings는 스마트 포인터의 퍼포먼스에 대한 설명이다.

 

Common Requirements

이러한 스마트 포인터의 클래스 템플릿은 템플릿 파라미터 T를 가진다. 이것은 스마트 포인터가 가리키는 오브젝트의 형태를 특정한다. 스마트 포인터의 행동은 T 형태의 오브젝트의 소멸자 또는 delete 연산자가 예외를 송출하는 경우는 미정의 이다.

스마트 포인터의 선언의 시점에서는 T에 불완전 형을 지정할 수도 있다. 그러나 스마트 포인터의 실체화의 관점으로부터 보면 T는 완전 형이 아니면 안 된다. 불완전 형의 삭제를 포함해 이 요구를 위협하는 모두를 진단하는(에러로서 취급하는 것)같은 구현이 필요하다.  checked_delete 함수 템플릿의 기술을 참고.

shared_ptr은 이 제한을 가지지 않고 멤버 함수의 상당수는 T가 완전한 형태인 것을 요구하지 않는 것에 주의해라.

 

Rationale

T으로의 요구는 handle-body(별명 pimpl) 이데엄이나 거기에 준하는 용법에 대해 최대한의 안전성을 제공할 수 있도록 주의 깊게 설계되고 있다. 이러한 용법에 대해 스마트 포인터는 T가 불완전 형인 번역 단위 중에서 사용된다.  handle-body 이데엄은 구현과 인터페이스를 분리해 인터페이스가 이용되는 번역 단위로부터 구현을 숨긴다. 이러한 용법에 있어서의 스마트 포인터의 사용법의 예가 각각의 스마트 포인터의 문서에서 설명되고 있다.

scoped_ptrT가 소멸 시에 완전한 형태인 것을 요구하지만 shared_ptr 은 그렇지 않은 것에 주의해라.

 

Exception Safety(예외 안전성)

이러한 스마트 포인터 클래스가 많은 함수는 만약 예외를 던질 수 있으면 「효과 없음」혹은 「이것, 이것 이외는 효과 없음」으로 명시되고 있다. 이것은 이러한 클래스의 하나의 오브젝트가 예외를 던졌을 때 프로그램 상태 모두가 결과적으로 예외를 발생한 함수가 불려 가기 전 상태와 같은 것을 의미하고 있다. 즉 발견할 수 있는 부작용이 없는 것을 보증하고 있다. 그렇지 않은 함수는 결코 예외를 던지지 않는다. 함수가 던지는 유일한 예외는 std::bad_alloc 이다( Tcommon requirements를 채우고 있는 것을 가정한다). 문서에 명시적으로 std::bad_alloc을 던질 가능성이 있으면 기록되고 있는 함수만이 이 예외를 던진다.

 

Exception-specifications(예외 사양)

예외 사양은 이용되지 않는다. exception-specification rationale을 참고.

모든 스마트 포인터 템플릿은 결코 예외를 던지지 않는 멤버 함수를 가지고 있다. 결코 예외를 던지지 않는다고 하는 것은 자기 자신에게 예외를 던지는 일도 예외를 던지는 다른 함수를 호출할 것도 없다고 하는 것이다. 이러한 멤버는 코멘트: //never throws 와 명시되고 있다.

가리켜진 오브젝트 형을 파괴(destroy)하는 함수는 common requirements에 의해 예외를 던지는 것을 금지되고 있다.

 

History and Acknowledgements

2002 1. Peter Dimov에 의해 4개의 클래스의 모두가 다시 만들었다. 기능의 추가와 버그의 수정을 해 각각의 클래스가 4개의 헤더 파일에 분할되었다.  weak_ptr가 추가되었다. 변경 개소에 대해서는 호환성 의 페이지를 참조해.

2001 5. Vladimir Prus에 의해 소멸 시에 있어서의 완전형의 필요성이 제안되었다.  Dave Abrahams,Greg Colvin,Beman Dawes,Rainer Deyke,Peter Dimov,John Maddock,Vladimir Prus,Shankar Sai 등을 포함해 행해진 평의에 의해 개선책이 도출되었다.

1999 11. Darin Adler에 의해 공유 스마트 포인터 형을 위한 operator ==,operator != std::swap,std::less의 특수화판이 제공되었다.

1999 9. Luis Coelho에 의해 shared_ptr::swap shared_array::swap가 제공되었다.

1999 4. 1999년의 4, 5월에 Valetin Bonnard David Abrahams에 의해 매우 많은 개선점에 대한 제안이 해진다.

1998 10. 1994년에 Greg Colvin에 의해 C++ 표준화 위원회에 클래스 auto_ptr 와 클래스 counted_ptr 가 제안되었다. counted_ptr은 현재의 scoped_ptr 이나 shared_ptr 와 거의 같은 것이다. 표준 문서의 94-168/N0555, 예외 안전 스마트 포인터(Exception Safe Smart Pointers)의 항에 해당된다. 위원회에 의해 라이브러리 워킹 그룹의 권고가 부결된 얼마 안되는 사례의 하나로서 counted_ptr는 기각되어 소유권의 양도의 시멘틱스는 놀랄 만한 일로 auto_ptr에 추가되었다.

1998년의 10개월에 행해진 Per Andersson, Matt Austern, Greg Colvin, Sean Corfield,  Pete Becker, Nico Josuttis, Dietmar K?l, Nathan Myers, Chichiang Wan, Judy Ward 등에 의한 회의에 있어서 Beman Dawes에 의해 당초의 시멘틱스를 safe_ptr counted_ptr 라는 이름으로 부활시키는 것이 제안되었다. 논의 중에서 4개의 클래스의 이름이 결정되어 std::auto_ptr의 인터페이스에 엄밀하게 준거할 필요는 없다고 하는 결론에 이르렀다. 그리고 각각의 함수의 서명과 시멘틱스가 결정되었다.

그 후의 3개월 이상 shared_ptr 을 위해서 몇 개의 구현이 숙고되어 boost.org의 메일링 리스트로 논의되었다. 구현에 관한 논의에서는 참조 카운트의 구현 방법에 대해 반복해 논해졌다. 참조 카운트를 스마트 포인터에 가리켜지는 오브젝트에 묶어 관리하는 방법과 가리켜지는 오브젝트와는 따로 관리하는 방법의 어느쪽에 있어서도 참조 카운트의 값이 보관 유지되지 않으면 안 된다. 그러기 위해서는 각각의 방법에 대해 크게 나누어 두 개의 구현이 생각되었다.

  • 직접적인 분리 카운터 : shared_ptr 오브젝트는 보관 유지하는 오브젝트에의 포인터와 카운터에의 포인터를 가진다.
  • 간접적인 분리 카운터 : shared_ptr 오브젝트는 헬퍼 오브젝트로의 포인터를 가져 그 헬퍼 오브젝트가 보관 유지하는 오브젝트에의 포인터와 카운터에의 포인터를 가진다.
  • 임베디드 결합 카운터 : 카운터를 보관 유지하는 오브젝트의 멤버로 한다.
  • 플레이스먼트 결합 카운터 : new 연산자의 조작으로 카운터를 묶는다.

위에 나열한 모든 구현에 장점과 단점이 있다. 그런데 우리는 직접적 및 간접적인 어프로치로 여러 가지 타이밍의 테스트를 실시했다. 그 결과 Intel PentiumCPU에 두어 불과 이지만 측정 가능한 성능차이를 검출할 수 있었다.  Kevlin Henney는 그의 논문 "Counted Body Techniques" 에서 이 일을 말하고 있다. Dietmar Kühl 는 템플릿의 부분 특수화를 이용한 우아한 구현으로 바꿀 기술을 제안하고 실험했다. 이것은 라이브러리의 유저의 취향에 응해 그 구현을 바꾼다고 하는 기술이다.

그러나 Greg Colvin Jerry Schwarz는 「라이브러리의 파라미터화는 유저를 경원 시킨다」라고 반론해 최종적으로 우리는 직접적인 구현을 채용하기로 결정했다.

1994년의 여름 Greg Colvin C++ 표준화 위원회에 auto_ptr 클래스 및 counted_ptr 클래스를 제안했다. counted_ptr은 현재의 scoped_ptr 이나 shared_ptr 에 잘 닮은 것이다.  [Col-94] 그러나 counted_ptr는 불 채용이 되어 놀랄 만한 일에 auto_ptr에 소유권을 양도하는 시멘틱스가 추가되었다. 이것은 라이브러리의 워킹 그룹의 권고가 전 위원회에서의 지지를 얻을 수 없었던 얼마 안되는 케이스의 하나이다.

References

[Col-94] Gregory Colvin, Exception Safe Smart Pointers (예외 안전 스마트 포인터), C++ committee document 94-168/N0555, 19947.

[E&D-94] John R. Ellis & David L. Detlefs, Safe, Efficient Garbage Collection for C++ ( C++에 있어서의 안전하고 효율적인 가베지 콜렉션 ), Usenix Proceedings, 1994 2. 이 논문은 위크 포인터에 관한 상세한 고찰과 문헌 목록을 포함한다.


$Date: 2003/08/19 14:15:50 $

Copyright (C) 1999 Greg Colvin and Beman Dawes. Copyright 2002 Darin Adler. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.

Japanese Translation Copyright (C) 2003 Kohske Takahashi, Ryo Kobayashi.
오리지날 및 이 저작권 표시가 모든 복제 안에 나타나는 한 이 문서의 복제, 이용 , 변경, 판매 그리고 배포를 인정한다. 이 문서는 「있는 그대로」 로 제공되고 있어 어떠한 명시적, 암묵적 보증도 실시하지 않는다. 그리고 어떠한 목적에 대해서도 그 이용이 적합한 것을 관여 하지 않는다.