2013-06-16 1 views
12

나는 스마트 포인터가없는 클래스를 사용하는 것을 방지하기 위해 노력해 왔습니다. 따라서 스마트 포인터에 의해 힙이 할당되고 관리되도록 오브젝트를 강제 설정하십시오. 는 이러한 결과를 얻기 위해서, 나는 다음 시도했다 : 꽤 잘 당신은 단지 클래스 사용자가 std::unique_ptr를 통해 클래스의 인스턴스를 조작 할 수있는 것인지스마트 포인터 인스턴스를 클래스에 강제로 적용하는 방법은 무엇입니까?

#include <memory> 
class A 
{ 
private : 
    ~A {} 
    // To force use of A only with std::unique_ptr 
    friend std::default_delete<A>; 
}; 

이 작품. 하지만 std::shared_ptr에서는 작동하지 않습니다. 그래서 당신이 그런 행동을 취할 수있는 아이디어가 있는지 알고 싶습니다.

#include <memory> 
class A 
{ 
private : 
    ~A {} 
    // For std::shared_ptr use with g++ 
    friend __gnu_cxx::new_allocator<A>; 
}; 

을하지만이 솔루션은 휴대용되지 않습니다 : 나는 다음을 수행한다 찾은 유일한 해결책은 (friend std::allocator_traits<A>;이 unsufficient이었다 사용). 어쩌면 내가 잘못하고있는 것 같아.

+0

좋은 솔루션 ... 좋아, 이건 STL에 대한 작동 못해하지만 난 항상 내 자신의 SharedPtr 구현을 위해 이것을 원했고 내 문제를 해결! – mmmmmmmm

답변

17

std::unique_ptr<A>을 반환하는 friend'd 팩토리 함수를 생성하고 클래스에 액세스 가능한 생성자가 없도록합니다. 그러나 사용할 수있는 소멸자합니다

#include <memory> 

class A; 

template <class ...Args> 
std::unique_ptr<A> make_A(Args&& ...args); 

class A 
{ 
public: 
    ~A() = default; 
private : 
    A() = default; 
    A(const A&) = delete; 
    A& operator=(const A&) = delete; 

    template <class ...Args> 
    friend std::unique_ptr<A> make_A(Args&& ...args) 
    { 
     return std::unique_ptr<A>(new A(std::forward<Args>(args)...)); 
    } 
}; 

을 이제 클라이언트는 분명히 얻을 수 unique_ptr<A> :

std::unique_ptr<A> p1 = make_A(); 

하지만 당신의 클라이언트는 그냥 쉽게 shared_ptr<A> 얻을 수 있습니다 :

std::shared_ptr<A> p2 = make_A(); 

때문에 std::shared_ptr을 할 수 std::unique_ptr에서 건설하십시오. 어떤 사용자가 작성한 스마트 포인터를 가지고 있다면, 그들이 가지고있는 모든 시스템과 상호 운용되도록 할 것은 std::shared_ptr는이 단지처럼 std::unique_ptr를 사용하는 생성자를 생성하고,이해야 할 매우 쉽습니다 :

template <class T> 
class my_smart_ptr 
{ 
    T* ptr_; 
public: 
    my_smart_ptr(std::unique_ptr<T> p) 
     : ptr_(p.release()) 
    { 
    } 
    // ... 
}; 
+1

좋은 답변입니다! 고마워, 그건 내 솔루션보다 훨씬 깨끗해. – Nemikolh

+4

'make_B()','make_C()'팩토리 함수가 필요한 공통 인터페이스에'B','C' 등의 클래스가 더 많이있을 때 정적 인 public 멤버 템플릿'T :: make()'. 이렇게하면 컴파일 타임에 타입리스트로부터 구체적인 타입의 make() 함수를 등록 할 수있는 본격적인 팩토리 + 레지스트리 클래스를 조금 더 쉽게 설정할 수 있습니다. – TemplateRex

+0

@TemplateRex : 동의 함. 공장 기능을위한 훌륭한 명명 규칙입니다. –

0

"스마트 포인터"라는 일반적인 용어가 없으므로 원하는 것은 불가능합니다.

당신이 할 수있는 일은 알려진 스마트 포인터 세트를 지원하는 것입니다. 일반적인 솔루션은 ctor 또는 dtor를 비공개로 설정하고 공장 기능을 추가합니다. 원하는 스마트 포인터로 채워진 인스턴스를 반환 할 수 있습니다. unique_ptr과 shared_ptr을 지원하기를 원한다면 두 개의 팩토리 함수를 거의 필요로하지 않습니다. (그 포인터는 간단한 인터페이스를 통해 원시 포인터를 밀수함으로써 컨트롤이 가득 차지 않도록합니다.)