부스트의 shared_ptr(shared_ptr<Y> const & r, T * p)는 무엇에 사용됩니까?
-
05-07-2019 - |
문제
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_ptr
util.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스마트 포인터 객체에서 직접 변환 할 수 있으며이 두 가지 방법 모두 수동으로 캐스팅되는 원시 포인터 방식보다 훨씬 안전합니다.