2016-10-08 4 views
0
binden

Sagen wir, ich habe diesen Code:std :: get_deleter auf std :: shared_ptr mit std initialisiert ::

class BaseObject 
{ 
public: 
    virtual void OnDestroy() {} 
}; 
template <typename T> 
struct myArrayDeleter 
{ 
    void operator()(T *p, std::size_t count) 
    { 
     for(std::size_t i = 0; i < count; i++) 
     { 
      static_cast<BaseObject*>((void*)(int(p) + sizeof(T) * i))->OnDestroy(); 
     } 
     delete [] p; 
    } 
}; 

Und nehmen wir an, dass es wie vorgesehen funktioniert (es ist eine vereinfachte Version, geschrieben jetzt ohne die überprüfe aber im Grunde weißt du, was dieser Code tun soll).
Mit diesem Teil habe ich kein Problem. Aber check this out:

class AActor 
    : public BaseObject 
{ 
public: 
    virtual void OnDestroy() override 
    { 
     // some code here 
    } 
}; 

template <typename T> 
class SimplifiedHolder 
{ 
protected: 
    std::shared_ptr<T> m_shared; 
    std::size_t m_size; 
public: 
    // Some not important code here 

    // WE ASSUME HERE THAT IT ALWAYS HOLDS ARRAY 
    // sizeOfArray always > 1 
    template <typename U> 
    SimplifiedHolder(U *ptr, std::size_t sizeOfArray) 
     : m_size(sizeOfArray) 
    { 
     m_shared = std::shared_ptr<T>(ptr, 
          std::bind(&myArrayDeleter<U>(), std::placeholders::_1, m_size)); 
    } 

    // And now as we initialize our shared_ptr with template 
    // we can check if it is exactly of type "U" 
    template <typename U> 
    bool IsExactlyOfType() 
    { 
     if(!m_shared) 
      return false; 

     return ((void*)std::get_deleter<myArrayDeleter<U>>(m_shared)) != nullptr; 
    } 
}; 

Jedoch ist das Verfahren IsExactlyOfType nicht funktioniert. Das liegt daran, dass ich mit std::bind initialisiert habe. std::get_deleter gibt immer nullptr zurück, da der falsche Typ in der Vorlage angegeben ist. Ich weiß nicht, welchen Typ ich weitergeben soll. Ich habe auch versucht mit Nicht-Array-Code, in dem myDeleter ein Funktor mit nur einem Argument ist, und es funktioniert perfekt mit dem Code wie folgt aus:

template <typename U> 
bool IsExactlyOfType() 
{ 
    if(!m_shared) 
     return false; 

    return ((void*)std::get_deleter<myDeleter<U>>(m_shared) != nullptr; 
} 

Ich weiß, dass ich mit typeid(U) == typeid(*m_shared.get()) gehen könnte, aber das ist nicht das, was ich will. Ich habe viel komplizierteren Code und in diesem Fall ist nur diese Methode gut.

Kann ein erfahrener Programmierer mir sagen, welche Art zu std::get_deleter angeben?

+0

In Ihrem Deleter, was, wenn ein Zeiger nicht in ein 'int' passen kann? Wenn 'sizeof (T *)> sizeof (int)'? Warum nicht einfach '& p [i]' benutzen? –

+0

Nun, wie ich schrieb, ist es im Code ziemlich kompliziert, und es funktioniert im Grunde wie beabsichtigt und das ist nicht der Punkt hier. Der Punkt ist, ich weiß nicht, welcher Typ für std :: get_deleter angegeben werden soll. – RazzorFlame

+0

Ich hoffe immer noch, dass Sie nicht einen Cast wie 'int (p)' in Ihrem echten Code verwenden. Es wird *** fast alle 64-Bit-Systeme durchbrechen. –

Antwort

0

Es stellte sich heraus, dass der Compiler decltype nicht korrekt übersetzt hat. Ich versuchte Deleter sofort nach der Initialisierung von shared_ptr zu bekommen und es funktionierte. Derselbe Dekoltyp in der Funktion erzeugte jedoch einen anderen Typ. Ich habe es in Debugger und diese Ergebnisse erzeugt:

Im Konstruktor:

std::_Binder<std::_Unforced,grim::impl::TObjectArrayDeleter<APlayer>,std::_Ph<1> const &,unsigned int &> & 

In Funktion:

std::_Binder<std::_Unforced,grim::impl::TObjectArrayDeleter<APlayer>,std::_Ph<1> const &,unsigned int const &> * 

am Ende Werfen Sie einen Blick - es beigefügten zusätzlichen konst. Ich musste es manuell ändern, so sieht mein Code jetzt so aus:

using D = std::_Binder<std::_Unforced,grim::impl::TObjectArrayDeleter<U>, 
         std::_Ph<1> const &,unsigned int &>; 

return ((void*)std::get_deleter<D>(m_shared)) != nullptr; 
Verwandte Themen