2013-07-30 4 views
7

일부 C++ 11 std::unique_ptr 사용 및 gotchas 무엇입니까?일부 std :: unique_ptr 사용 및 "gotchas"

std::unique_ptr도 동적으로 할당 된 배열을 저장할 수 있습니까?

std::unique_ptr을 사용자 지정 삭제 메커니즘을 사용하는 리소스와 함께 사용할 수 있습니까?

답변

18

Q & A 형식을 사용하여 몇 가지 용도와 기능을 정리해 보겠습니다.


Q1 : 나는 내 수업 X 내부 클래스 Component포인터를 저장하고 싶습니다.
"컨테이너"클래스 X을 복사 할 수 없습니다. XComponent 인스턴스의 유일한 소유자입니다.
나는 소유원시 포인터가 나쁜 일 및 "leaktrocities"의 잠재적 인 소스입니다 ( 원시 포인터를 관찰하는 대신 괜찮) 것을 알고있다. 무엇을 스마트 포인터이 목적으로 사용할 수 있습니까? A1

: C++ (11)의 std::unique_ptr 확실히 좋은 방법입니다.

고유 한 (비공유) 소유권의 경우에는 문제가 없으며 std::shared_ptr의 오버 헤드가 없습니다.
이전 C++ 98/03 boost::scoped_ptr에 대한 탁월한 대체품입니다.
사실, 또한 std::unique_ptr이동 의미을 제공합니다.
Xunique_ptr<Component> 데이터 멤버 (및 기타 이동 가능 데이터 멤버)가 포함 된 경우 전체 클래스 X이 자동으로이됩니다.

#include <memory> // for std::unique_ptr 

class X 
{ 
    std::unique_ptr<Component> m_pComponent; 
    .... 

public: 
    X() 
     : m_pComponent(new Component()) 
    { 
     .... 
    } 
} 

(. 물론, 스마트 포인터되고, 명시 적으로 포함하는 클래스의 소멸자에서 삭제 할 필요가 없습니다)


:

예 사용은 아래로 보여 질문 2 : 대단합니다! 명시 적 소멸자가 필요없고, 아무런 덧씌우개가 필요 없습니다. (일반적인 C++ 철학 : "우리가 사용하지 않는 것에 대해서는 돈을 내지 않습니다"), 이미 구현 된 의미 체계를 옮깁니다!
그러나 문제가 있습니다. 내 클래스 Component에 생성자 오버로드가있어서 Component 인스턴스를 만들기 전에 생성자 코드에서 계산해야하는 매개 변수가 필요합니다.나는 unique_ptr 새로 만든 Component을 지정 생성자에서 통상의 operator=의 할당은을 사용하여 시도,하지만 오류 메시지가 있어요 :

X::X() 
{ 
    .... 

    const int param = CalculateCoolParameter(); 

    // This assignment fails: 
    m_pComponent = new Component(param); // <---- Error pointing to '=' here 
       ^--- error 
} 

A2 : OK, 아마 당신이 기대했던 이전의 해제 operator= 과부하가 소유를 포인터 (있는 경우)와 새로 생성 된 포인터에 할당합니다.
불행히도 이러한 과부하는 없습니다.
그러나 std::unique_ptr::reset() 방법을 사용합니다.

m_pComponent.reset(new Component(param)); 

Q3 : 이봐! 이 unique_ptr 정말 멋지다! 나는 그것이 영리하다는 것을 좋아한다, 그것은 자동적으로 움직일 수 있고, 머리 위를 가져 오지 않는다.
그래서 std::vector을 사용하는 대신 동적으로 할당 된 배열 (런타임시 계산 됨)을 저장하고 싶습니다. (코드의이 부분에서 나는 매우 제한적이며, 그렇지 않습니다. 모든 std::vector의 동적 크기 조정 기능, 딥 복사 등을 원하지 않기 때문에 std:vector 오버 헤드 비용을 지불하고 싶습니다. 대신 내가 count 소멸자 호출을 예상

const size_t count = GetComponentsCount(); 
unique_ptr<Component> components(new Component[count]); 

그것은 잘 컴파일,하지만 난 ~Component 소멸자 만 라고 주목 :

나는 이런 식으로 뭔가를 시도! 여기서 뭐가 잘못 됐어?

A3

: 문제는 상기 구문, std::unique_ptr 할당 된 객체를 방출 delete를 사용한다는 것이다. 그러나 이들이 new[]을 사용하여 할당되었으므로 올바른 정리 전화는 delete[] (괄호가없는 delete이 아님)입니다.

이 문제를 해결하려면 제대로 리소스를 해제하기위한 delete[]를 사용하는 unique_ptr를 지시는 다음 구문을 사용해야합니다 :

unique_ptr<Component[]> components(new Components[count]); 
//     ^^ 
// 
// Note brackets "[]" after the first occurrence of "Component" 
// in unique_ptr template argument. 
// 

Q4 : 좋아요! 그러나 나는 (fopen() 연) C <stdio.h> 파일 fclose(), 또는 CloseHandle()처럼, 자원 해제 코드가 일부 사용자 정의 정리 기능를 사용하는 대신 일반 C++ delete (또는 delete[])를 사용하지만, 수행되지 않는 경우에 unique_ptr도 사용할 수 있습니다 Win32 파일 HANDLE (CreateFile()을 사용하여 생성)에 대해?

A4는 : 그것은 확실히 가능합니다 : 당신이 std::unique_ptr에 대한 사용자 정의 Deleter가을 지정할 수 있습니다.

:

// 
// Custom deleter function for FILE*: fclose(). 
// 
std::unique_ptr<FILE,   // <-- the wrapped raw pointer type: FILE* 
       int(*)(FILE*)> // <-- the custom deleter type: fclose() prototype 
myFile(fopen("myfile", "rb"), // <-- resource (FILE*) is returned by fopen() 
     fclose);    // <-- the deleter function: fclose() 



// 
// Custom deleter functor for Win32 HANDLE: calls CloseHandle(). 
// 
struct CloseHandleDeleter 
{ 
    // The following pointer typedef is required, since 
    // the raw resource is HANDLE (not HANDLE*). 
    typedef HANDLE pointer; 

    // Custom deleter: calls CloseHandle(). 
    void operator()(HANDLE handle) const 
    { 
     CloseHandle(handle); 
    } 
}; 

std::unique_ptr<HANDLE, CloseHandleDeleter> myFile(CreateFile(....)); 
+0

FWIW, 사용하지 않는 벡터 기능에 대해 어떻게 지불합니까? (힌트 : 아무 것도) –

+0

적어도 메모리 풋 프린트로부터,'std :: vector'는 3 개의 포인터를 사용할 수 있습니다. 대신에 'unique_ptr' 하나만 사용할 수 있습니다. –

+0

A2 : 가능한 한 더 좋은 해결책은 계산을 수행하고 std :: unique_ptr을 반환하는 메서드를 갖는 것입니다. 그런 다음 이니셜 라이저 목록에서 해당 값을 사용하십시오. – stijn