共享指針非常聰明。他們記得他們最初構建的類型,以便正確刪除它們。採取這一例如:可否將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類型。
例如:
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::shared_ptr
,當您使用std::make_shared
,在缺失者必須類似於這樣的功能:[](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的完美設計。 +1 :) –
@RichardHodges我喜歡'std :: unique_ptr',因爲它們在開銷方面是免費的;)。至於答案,好@rodrigo,它幾乎涵蓋了一切。 –
'shared_ptr' *確實包含一個指針,一個從'shared_ptr :: get()'返回的指針。但是這不是傳遞給刪除者的指針。 –