2010-04-15 3 views
3

가장 일반적으로 재사용 가능한 참조 카운트 된 개체는 재사용을 구현하기 위해 개인 상속을 사용합니다. 나는 개인 상속의 거대한 팬이 아니에요,이 일을 처리 허용 방법입니다 있을지 궁금 :구성을 통해 참조 횟수를 구현하는 것이 괜찮습니까?

class ReferenceCounter { 
    std::size_t * referenceCount; 
public: 
    ReferenceCounter() 
     : referenceCount(NULL) {}; 
    ReferenceCounter(ReferenceCounter& other) 
     : referenceCount(other.referenceCount) { 
      if (!referenceCount) { 
       referenceCount = new std::size_t(1); 
       other.referenceCount = referenceCount; 
      } else { 
       ++(*referenceCount); 
      } 
    }; 
    ReferenceCounter& operator=(const ReferenceCounter& other) { 
      ReferenceCounter temp(other); 
      swap(temp); 
      return *this; 
    }; 
    void swap(ReferenceCounter& other) { 
     std::swap(referenceCount, other.referenceCount); 
    }; 
    ~ReferenceCounter() { 
     if (referenceCount) { 
      if (!*referenceCount) 
       delete referenceCount; 
      else 
       --(*referenceCount); 

     } 
    }; 
    operator bool() const { 
     return referenceCount && (*referenceCount != 0); 
    }; 
}; 

class SomeClientClass { 
    HANDLE someHandleThingy; 
    ReferenceCounter objectsStillActive; 
public: 
    SomeClientClass() { 
     someHandleThingy = RegCreateKeyEx(...); 
    } 
    ~SomeClientClass() { 
     if (objectsStillActive) 
      return; 
     RegCloseKey(someHandleThingy); 
    }; 
}; 

가 아니면이 보이지 않아요이 미묘한 문제가?

편집
나는이 특정 구현 슈퍼아요 걱정하지 않아요 (아마 버그가 - 내가 생산 코드에서이 같은 것을 사용하기 전에 shared_ptr의의 내장을보고 시간을 보낼거야) - 나는 단지 일반적으로 재사용 가능한 참조 계산 케이크가 항상 구성보다는 상속을 사용하여 구현 된 것 같다 특정 이유가 있다면 걱정입니다.

답변

3

핸들을 복사 할 때 카운터를 복사해야합니다. 템플릿에 운영 체제 유형을 전달하지 않으려 고 할지도 모르겠지만 여기서 안전은 상속이 필요하다고 생각합니다. (비록 상속이 HANDLE에서 발생합니다.)

HANDLE은 POD이기 때문에 특별한 경우 일 수 있습니다. 본질적으로 T* 외의 유형의 포인터가 있습니다.

숫자가 0이 될 때 delete 이외의 것을 원한다는 동기가 있습니다. 적응은 smart_ptr 일 가능성이 높습니다. 그리고 그다지 멀지 않을 수도 있습니다.

+0

그런 경우 A. referenceCount 객체가 복사되었으므로 (referenceCount가 NULL 포인터가 아니기 때문에) B. referenceCount는 그룹의 마지막 ReferenceCount를 파괴하고 있음을 나타내는 0입니다. 따라서 size_t 포인터의 할당을 해제해야합니다. –

+0

@Billy :하지만 이제 카운터를 지웠으므로 컨트롤 개체를 삭제할지 여부를 결정하기 위해 카운터를 읽을 수 없습니다. 참조 카운트 된 것으로 보이는 유일한 것은 카운터 자체입니다. 내가 인터페이스의 일부 지점을 놓치고있는 것 같아요. – Potatoswatter

+0

마지막 ReferenceCount 개체가 파괴되는 경우 아무도 카운터에 다시 액세스하지 못합니다. –

0

나는 이것이 어떤 장점이 있다고 생각하지 않습니다. 참조 카운팅은 공유 개체에 대해서만 의미가 있습니다. 목표는 힙 할당 및/또는 다른 것들 사이의 복사에 저장하는 것입니다. 사실 복사 카운터을 구현했습니다. 카운터 값을 쿼리하기위한 인터페이스를 제공하지 않기 때문에 유용하지 않습니다. boost::intrusive을 다시 방문하시는 것이 좋습니다.

+0

그 인터페이스는'operator bool'이며, 이는 ReferenceCount 객체가 마지막으로 남아있는'ReferenceCount' 객체인지 여부를 반환합니다. 침입을 촉진하려면 여전히 복사가 필요하지 않을 때 피해야하는 힙 할당이 필요합니다. –

0

실제로 HANDLE 클래스 외부의 HANDLE에 대한 참조 계산을 구현 중입니다 ... shared_ptr에 지긋 지긋합니다.

참조 계산을 구현하기위한 구성을 사용하는 것이 좋습니다. 참조 계산 개체 ReferenceCounter이 클래스 HANDLE 인스턴스를 소유하는 것이 더 좋을지라도 ... 사용량이 훨씬 더 안전하며 삭제 루틴 만 구현하기 때문에 재사용하기가 더 저렴합니다. 모든 생성자 (arg)에서 수행하는 대신 한 번.

개인 상속을 사용하는 단일 타당한 이유는 Empty Base Optimization이며, 다른 모든 경우는 커플 링 측면에서 훨씬 뛰어난 구성으로 처리 될 수 있으므로 그렇게 할 이유가있을 확률은 적습니다. 잘못지도하거나 게으름에서.

+0

"사용법이 훨씬 안전하고 모든 생성자 (arg)에서 삭제 루틴을 한 번만 구현하기 때문에 재사용이 저렴합니다." <- 이것을 사용하는 모든 클라이언트는 HANDLE 객체의 유일한 관리자가됩니다. 이러한 클라이언트 클래스의 모든 생성자는 WindowsAPI 함수를 호출하고 핸들을 RAII 클래스에 저장하는 간단한 프론트 엔드가됩니다. EBO는 여기서는 유용하지 않습니다. 왜냐하면 참조 계산 클래스가 포인터의 크기를 저장해야하기 때문입니다. –

관련 문제