공유 포인터는 매우 똑똑합니다. 그들은 올바르게 삭제하기 위해 처음에 만들어 낸 유형을 기억합니다. 예를 들면 가져가 :shared_ptr를 <T>의 shared_ptr에 업 캐스팅 할 수 있습니까? <void>가 정의되지 않은 동작을 일으킬 수 있습니까?
이struct A { virtual void test() = 0; };
struct B : A { void test() override {} };
void someFunc() {
std::shared_ptr<A> ptr1;
ptr1 = std::make_shared<B>();
// Here at the end of the scope, B is deleted correctly
}
그러나, 무효 포인터에 문제가있을 것 같다 무효 포인터의 내리 뜬가 유효하려면, 하나는 원래부터 upcasted 된 유형으로 다운 캐스트해야합니다. 예를 들어
: std::shared_ptr
와
void* myB = new B;
// Okay, well defined
doStuff(static_cast<B*>(myB));
// uh oh, not good!
// For the same instance of a child object, a pointer to the base and
// a pointer to the child can be differrent.
doStuff(static_cast<A*>(myB));
, 당신은 std::make_shared
를 사용할 때 Deleter가이 기능과 유사합니다 [](B* ptr){ delete ptr; }
. 포인터 (첫 번째 예제에서)는 A
에 대한 포인터에 B
인스턴스를 보유하고 올바르게 삭제하기 때문에 어떤 식 으로든이를 내 버려야합니다.
제 질문은 : 다음 코드 단편은 정의되지 않은 동작입니까?
void someFunc() {
{
std::shared_ptr<void> ptr = std::make_shared<B>();
// Deleting the pointer seems okay to me,
// the shared_ptr knows that a B was originally allocated with a B and
// will send the void pointer to the deleter that's delete a B.
}
std::shared_ptr<void> vptr;
{
std::shared_ptr<A> ptr = std::make_shared<B>();
// ptr is pointing to the base, which can be
// different address than the pointer to the child.
// assigning the pointer to the base to the void pointer.
// according to my current knowledge of void pointers,
// any future use of the pointer must cast it to a A* or end up in UB.
vptr = ptr;
}
// is the pointer deleted correctly or it tries to
// cast the void pointer to a B pointer without downcasting to a A* first?
// Or is it well defined and std::shared_ptr uses some dark magic unknown to me?
}
나는 항상 shared_ptr의 디자인 완성도를 전달하는 정답을 upvote 할 것이다. +1 :) –
@RichardHodges 나는 오버 헤드의 관점에서 무료이므로'std :: unique_ptr'을 선호한다. 대답은, 좋은 직업 @rodrigo, 그것은 거의 모든 것을 다룹니다. –
'shared_ptr' *는 shared_ptr :: get()에서 반환 된 포인터를 가지고 있습니다. 그러나 이것은 Deleter에게 전달되는 포인터가 아닙니다. –