2009-03-10 2 views
4

몇 가지 관련 개체 유형에 대한 참조를 제공하는 라이브러리를 작성했습니다. 이러한 모든 객체는 내부적으로 라이브러리에 의해 관리되며 수명은 boost::shared_ptr라이브러리 인터페이스에서 weak_ptr에 대한 액세스를 제공하는 것이 현명합니까?

입니다. 라이브러리의 사용자는 노출 된 객체의 수명도 알 수 있습니다. 따라서 포인터를 저장하거나 이러한 객체에 대한 참조를 유지할 수 있습니다. 그들이 이것을하고 그 물체가 더 이상 유효하지 않을 때를 알는 것은 합리적 일 것입니다.

하지만 유감스럽게도 내 사용자가 합리적이라고 생각합니다.

라이브러리에 weak_ptr의 객체를 노출시키는 것이 허용됩니까? 다른 도서관에서 해본 적이 있습니까?

나는이 라이브러리의 사용법을 어플리케이션에서 프로파일 링했으며, weak_ptr을 독점적으로 드러내는 것은 너무 중요한 일임을 발견했습니다.

어떤 자체에 weak_ptr 노출시킬 오브젝트 일치 API 함수 또는 weak_ptr은 기준 중 하나를 노출하거나 할 필요가 지혜롭게 있을까?

+0

weak_ptrs를 노출해야하는지 묻는다면, 프로파일 링을 통해 어디서나 weak_ptrs를 사용할 수 없다는 것을 알 수 있습니다 - 맞습니까? 성능이 중요한 경우에는 무엇을 대신 제공 하시겠습니까? 원시 참조? 또는 shared_ptr? –

+0

@j_random_hacker : 라이브러리가 이미 참조를 노출합니다. 참조 또는 weak_ptr 중 하나를 노출하는 API 함수를 비교하는 것을 고려하고 있습니다. –

+0

흠. 실수를 감지하도록 호출 코드를 얻으려고하기 때문에 shared_ptrs 대신 weak_ptrs를 제안하는 것 같습니다. 맞습니까? 하지만 호출 코드가 weak_ptr을 shared_ptr로 바꾸어야한다고 생각하기 때문에 많은 보호 기능을 구매하지 않아도됩니다. ... –

답변

6

이미 smart_ptr에 라이브러리 사용자가 직접 액세스 할 수있는 경우 해당 weak_ptr의 생성자를 통해 weak_ptr에 액세스 할 수 있습니다. 그러나 smart_ptr이 모두 라이브러리 내부에 있다면 이는 다른 이야기입니다.

그런 경우 라이브러리에서 제공하는 다른 액세스 외에도 각 개체가 weak_ptr을 전달하도록하는 것이 좋습니다. 이는 사용자에게 유연성을 제공합니다. weak_ptr이 필요하면 즉시 액세스 할 수 있습니다. shared_ptr이 필요하면 쉽게 얻을 수 있습니다. 객체 자체에 대한 액세스 만 필요하면 스마트 포인터를 완전히 무시할 수 있습니다.

물론 라이브러리가 무엇인지 또는 어떻게 사용되거나 디자인되었는지는 알 수 없습니다. 그게 내 추천을 바꿀 수도있어.

+0

라이브러리는 현재 shared_ptr을 내부적으로 만 사용합니다. –

1

특히 약 TR1 has similar smart pointers (PDF)을 사용하면 weak_ptrs가 노출되는 데 아무런 문제가 없습니다.

TR1은 Visual Studio 및 GCC에서 주로 구현되지만 일부 다른 컴파일러에서는 구현되지 않습니다. 그러나 당신이 신경 쓰는 모든 컴파일러에서 구현 될 때 API를 재 작업하여 대신 스마트 포인터를 노출 할 수 있습니다.

2

클라이언트에게 weak_ptr에 대한 액세스 권한을 부여한 경우 클라이언트를 잠 가서 shared_ptr을 생성하고 개체 삭제가 지연 될 수 있습니다. 이로 인해 라이브러리에 문제가 발생할 수 있습니다.

다른 클래스에 weak_ptr을 배치하고 발신자에게 shared_ptr을 지정하는 것이 좋습니다. 그렇게하면 weak_ptr<T>::lock()으로 전화 할 수 없습니다. 성능에 제약이있어 구현 방법에 영향을 미칠 수 있지만, shared_ptr<InterfaceClass>을 사용하면 라이브러리에 weak_ptr 클래스를 유지하는 것이 좋습니다.

그런 식으로 라이브러리 인터페이스에서 이러한 구현 세부 사항을 유지하고 인터페이스를 변경하지 않고 구현하는 방법을 변경할 수 있습니다.

4

라이브러리 개체를 가져 오는 복잡한 메커니즘으로 인해 사람들이 라이브러리를 사용하지 않게됩니다. 라이브러리의 의미가 weak_ptrs를 사용하는 사람들을 필요로한다면, 어떤 점에서 객체가 사라질 수도 있다는 것을 알지 못한다. 인터페이스가 가능한 한 라이브러리의 사용법에 대한 많은 정보를 표현하고, 문서를 보존하며, 무한히 사용하기 쉽게 만듭니다.

불량 사용자를 대상으로 디자인 할 수 없습니다.

0

라이브러리의 유효하지 않은 사용 (삭제시 개체에 액세스하려고 함)과 고성능 API (API에 weak_ptr 및 shared_ptr 없음)를 함께 트래핑하려는 경우 디버그와 nondebug 빌드를위한 다른 API가 있어야합니다.

당신이 노출하는 객체의 단 하나의 클래스 만 가지고 있다고 가정 해보자. 이 클래스 Object를 호출합니다. 내부 오브젝트에 액세스하기 위해 API에서 리턴 한 포인터 유형은 다음과 같이 정의됩니다.

#ifdef DEBUG 
typedef ObjectPtrFacade ObjectPtr 
#else 
typedef Object * ObjectPtr; 
#endif 

여기서 facade는 사용자가 작성한 클래스입니다. 그것은 대략 다음과 같이 작동합니다 : 당신이 디버깅 빌드를 만들 때마다

class ObjectPtrFacade { 
public: 
    ObjectPtrFacade(Object *o) : wptr(o) { } 
    // copy constructor and assignment here etc. (not written) 
    Object * operator ->() const { return access(); } 
    Object & operator *() const { return *access(); } 
private: 
    Object * access() { 
     assert(wptr.use_count() > 0); 
     return (Object *)(wptr.lock()); 
    } 
    weak_ptr<Object> wptr; 
} 

을 이러한 방법으로, 당신은 그 use_count()가 이상 0이 개체에 액세스하기 전에 주장 사용중인 스마트 포인터의 특별한 종류를 즉 객체가 여전히 존재한다는 것입니다. 객체가 릴리즈 되었다면 실패한 assert를 얻습니다. 이것은 널 포인터 참조보다 낫습니다.

일반적으로 weak_ptr을 사용하면 weak_ptr이 shared_ptr을 반환 한 후에도 lock()을 호출하고 null 포인터 참조를 만들 수 있기 때문에 API 사용자가 "바보"인 경우 도움이되지 않습니다. 비어 있습니다 ...