문제

boost::shared_ptr 특이한 생성자가 있습니다

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);

그리고 나는 이것이 무엇에 유용할지 조금 의아해합니다.기본적으로 소유권을 공유합니다. r, 하지만 .get() 돌아올 것이다 p. ~ 아니다 r.get()!

이는 다음과 같은 작업을 수행할 수 있음을 의미합니다.

int main() {
    boost::shared_ptr<int> x(new int);
    boost::shared_ptr<int> y(x, new int);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

그리고 당신은 이것을 얻을 것입니다 :

0x8c66008
0x8c66030
2
2

포인터는 별개이지만 둘 다 포인터가 있다고 주장합니다. use_count 2개(동일한 개체의 소유권을 공유하므로).

그래서 int 에게 소유 된 x 한은 존재할 것이다 x 또는 y 주위에 있습니다.그리고 내가 문서를 올바르게 이해했다면 두 번째 int 결코 파괴되지 않습니다.다음 테스트 프로그램을 통해 이를 확인했습니다.

struct T {
    T() { std::cout << "T()" << std::endl; }
    ~T() { std::cout << "~T()" << std::endl; }
};

int main() {
    boost::shared_ptr<T> x(new T);
    boost::shared_ptr<T> y(x, new T);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

이는 예상대로 다음과 같이 출력됩니다.

T()
T()
0x96c2008
0x96c2030
2
2
~T()

그래서...하나의 포인터의 소유권을 공유하는 이 특이한 구성의 유용성은 무엇입니까? 행위 사용될 때 다른 포인터(소유하지 않은)와 같습니다.

도움이 되었습니까?

해결책

클래스 멤버를 공유하려는 경우 유용하며 클래스 인스턴스는 이미 다음과 같이 Shared_PTR입니다.

struct A
{
  int *B; // managed inside A
};

shared_ptr<A>   a( new A );
shared_ptr<int> b( a, a->B );

그들은 사용 수와 물건을 공유합니다. 메모리 사용에 대한 최적화입니다.

다른 팁

확장하기 위해 Leiz 's 그리고 Piotr 's 답,이 설명 shared_ptr<> 'aliasing'은 WG21 용지에서 나온 것입니다. "개선 shared_ptr C ++ 0X의 경우, 개정 2 ":

III. 별칭 지원

고급 사용자는 종종 생성 능력이 필요합니다 shared_ptr사례 p 다른 사람과 소유권을 공유합니다 (마스터) shared_ptr q 그러나 기초가 아닌 물체를 가리 킵니다. *q. *p 회원 또는 요소 일 수 있습니다 *q, 예를 들어. 이 섹션에서는이 목적으로 사용할 수있는 추가 생성자를 제안합니다.

이러한 표현력 증가의 흥미로운 부작용은 이제 *_pointer_cast 기능은 사용자 코드로 구현할 수 있습니다. 그만큼 make_shared 이 문서의 뒷부분에 제시된 공장 기능은 공개 인터페이스 만 사용하여 구현할 수도 있습니다. shared_ptr 별칭 생성자를 통해.

타격:

이 기능은 인터페이스를 확장합니다 shared_ptr 표현력을 높이고 C ++ 0X 표준에 추가되는 것이 좋습니다. 소스 및 이진 호환성 문제를 도입하지 않습니다.

제안 된 텍스트 :

추가 shared_ptrutil.smartptr.shared] 다음 생성자 :

template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );

util.smartptr.shared.const]에 다음을 추가하십시오.

template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );

효과 : 구성 a shared_ptr 저장 인스턴스 p 그리고 소유권을 공유합니다 r.

결제 후 : get() == p && use_count() == r.use_count().

던지기 : 아무것도 아님.

메모: 매달려있는 포인터의 가능성을 피하려면이 생성자의 사용자가 p 소유권 그룹까지 최소한 유효합니다 r 파괴됩니다. -엔드 노트.

메모: 이 생성자는 AN의 생성을 허용합니다 비어 있는 shared_ptr널이 아닌 저장 포인터가있는 인스턴스. -엔드 노트.

이것을 사용하여 동적 캐스트 포인터를 유지할 수도 있습니다.

class A {};
class B: public A {};

shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));

하위 레벨 API 또는 기타 수단으로 추가 데이터를 할당 할 수있는 일부 드라이버 또는 하위 레벨 API의 데이터 구조에 대한 포인터가있을 수 있습니다. 이 경우 USE_COUNT를 늘리는 것이 흥미로울 수 있지만 첫 번째 포인터가 다른 데이터 포인터를 소유 한 경우 추가 데이터를 반환합니다.

내 작은 라이브러리에서 shared_ptr의 앨리어싱 생성자를 사용했습니다.

http://code.google.com/p/infectorpp/ (그냥 간단한 IoC 컨테이너)

요점은 (유형을 모르는) 다형성 클래스에서 반환되기 위해 알려진 유형의 shared_ptr이 필요했기 때문입니다.shared_ptr을 필요한 유형으로 암시적으로 변환할 수 없었습니다.

파일에서 "InfectorHelpers.hpp"(72-99행) IAnyShared 유형에 대해 실제로 작동하는 것을 볼 수 있습니다.

별칭 생성자는 실제로 가리키는 포인터를 삭제하지 않는 shared_ptr을 생성하지만 그들은 여전히 ​​참조 카운터를 증가시킵니다 원본 개체에 추가하면 매우 유용할 수 있습니다.

기본적으로 앨리어싱 생성자를 사용하여 모든 항목에 대한 포인터를 만들고 이를 참조 카운터로 사용할 수 있습니다.

//my class
std::shared_ptr<T> ist;
int a; //dummy variable. I need its adress

virtual std::shared_ptr<int> getReferenceCounter(){
    return std::shared_ptr<int>(ist,&a); //not intended for dereferencing
}

virtual void* getPtr(); //return raw pointer to T

이제 우리는 "참조 카운터"와 T의 인스턴스에 대한 포인터를 모두 갖게 되었습니다. 이는 앨리어싱 생성자를 사용하여 무언가를 생성하기에 충분한 데이터입니다.

std::shared_ptr<T> aPtr( any->getReferenceCounter(), //share same ref counter 
               static_cast<T*>(any->getPtr()) ); //potentially unsafe cast!

나는 앨리어싱 생성자에 대해 이러한 용도를 고안한 척하지 않지만 다른 사람이 동일한 작업을 수행하는 것을 본 적이 없습니다.해당 더러운 코드가 작동하는지 추측하는 경우 대답은 '예'입니다.

을 위한 "shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));"

스마트 포인터를 사용하는 것이 권장되는 방법이 아니라고 생각합니다.

이 유형 변환을 수행하는 권장되는 방법은 다음과 같습니다.

shared_ptr<B> b(a);

부스트 문서에서는 다음과 같이 언급되어 있습니다.

shared_ptr<T> 암시 적으로 변환 될 수 있습니다 shared_ptr<U> t*가 암시 적으로 u*로 변환 될 수 있습니다. 특히, shared_ptr<T> 암시 적으로 변환 가능합니다 shared_ptr<T> const, 에게 shared_ptr<U> 여기서 u는 접근 가능한 t의 기저입니다. shared_ptr<void>.

그 외에도 우리는 또한 가지고 있습니다 dynamic_pointer_cast스마트 포인터 객체에서 직접 변환 할 수 있으며이 두 가지 방법 모두 수동으로 캐스팅되는 원시 포인터 방식보다 훨씬 안전합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top