共有ポインタはかなりスマートです。彼らは、それらを正しく削除するために最初に構築したタイプを覚えています。例えばそれを取る:しかし、空ポインタに問題があるように思わ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
を使用する場合、削除手段は、この機能に似て見なければならない:[](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に渡されるポインタと同じではありません。 –