web-dev-qa-db-fra.com

Comment peut-on abattre un std :: shared_ptr?

Considérer:

struct SomethingThatsABase
{
    virtual bool IsChildOne() const { return false; }
    virtual bool IsChildTwo() const { return false; }
};

struct ChildOne : public SomethingThatsABase
{
    virtual bool IsChildOne() const { return true; }
};

struct ChildTwo : public SomethingThatsABase
{
    virtual bool IsChildTwo() const { return true; }
};

void SomeClientExpectingAChildOne(std::shared_ptr<ChildOne> const& ptrOne)
{
    //Does stuff
}

void SomeClient(std::shared_ptr<SomethingThatsABase> const& ptr)
{
    if (ptr->IsChildOne())
    {
        SomeClientExpectingAChildOne(ptr); //Oops.
        //Hmm.. can't static_cast here, because we need a `shared_ptr` out of it.
    }
}

(Notez que je ne peux pas simplement faire une std::shared_ptr<ChildOne>(static_cast<ChildOne*>(ptr.get())), car alors le nombre de références n'est pas partagé entre les deux shared_ptr S)

59
Billy ONeal

Cela devrait fonctionner:

if (ptr->IsChildOne())
{
    SomeClientExpectingAChildOne(std::static_pointer_cast<ChildOne>(ptr));
}
85
mwigdahl

Le shared_ptr équivalent de static_cast est static_pointer_cast, et le shared_ptr équivalent de dynamic_cast est dynamic_pointer_cast.

34
Joel

À partir de C++ 11, le §20.10.2.2.9 ( [util.smartptr.shared.cast] ) de la norme C++ spécifie les équivalents de static_cast, const_cast et dynamic_cast pour que std::shared_ptr soit comme suit:

std::static_pointer_cast:

template <class T, class U>
shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r) noexcept;

static_pointer_cast Nécessite que static_cast<T *>(r.get()) soit bien formé. Si r est vide, un shared_ptr<T> Est renvoyé, sinon renvoie un pointeur w partageant la propriété avec rw.get() == static_cast<T *>(r.get()) et w.use_count() == r.use_count().

std::const_pointer_cast:

template <class T, class U>
shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r) noexcept;

const_pointer_cast A des exigences et une sémantique similaires à static_pointer_cast, Sauf que const_cast Est utilisé à la place de static_cast.

std::dynamic_pointer_cast:

template <class T, class U>
shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r) noexcept;

dynamic_pointer_cast Est un peu différent car il nécessite que dynamic_cast<T *>(r.get()) soit bien formé et ait une sémantique bien définie. Si dynamic_cast<T *>(r.get()) est une valeur non nulle, renvoie un pointeur w partageant la propriété avec rw.get() == dynamic_cast<T *>(r.get()) et w.use_count() == r.use_count(), sinon un shared_ptr<T> vide est retourné.

std::reinterpret_pointer_cast:

Pour C++ 17, N392 (adopté dans Library Fundamentals TS en février 2014 ) a également proposé un std::reinterpret_pointer_cast Similaire au précédent, qui ne nécessiterait que reinterpret_cast<T *>((U *) 0) pour être bien formé et renvoie shared_ptr<T>(r, reinterpret_cast<typename shared_ptr<T>::element_type *>(r.get())). Remarque N3920 a également modifié le libellé des autres transtypages shared_ptr Et étendu shared_ptr Pour prendre en charge les tableaux.

19
jotik