2016-10-08 4 views
0

Скажем, у меня есть этот код:станд :: get_deleter на станд :: shared_ptr инициализируется станд :: связать

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; 
    } 
}; 

И давайте предположим, что он работает как задумано (это упрощенная версия, написанная в настоящее время без проверьте, но в основном вы знаете, что должен делать этот код).
С этой частью у меня нет проблем. Тем не менее, проверить это:

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; 
    } 
}; 

Однако метод IsExactlyOfType не работает. Это потому, что я инициализировал shared_ptr с std::bind. std::get_deleter всегда возвращает nullptr, потому что неправильный тип указан в шаблоне. Я не знаю, какой тип пройти. Я пробовал также с кодом, не являющийся массивом, в котором myDeleter функтор только с одним аргументом, и это прекрасно работает с кодом, как это:

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

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

Я знаю, что я мог бы пойти с typeid(U) == typeid(*m_shared.get()), но это не то, что я хочу. У меня гораздо более сложный код, и в этом случае только этот метод хорош.

Может ли более опытный программист сказать мне, какой тип указывать на std::get_deleter?

+0

В вашем делете, что, если указатель не может поместиться в 'int'? Если 'sizeof (T *)> sizeof (int)'? Почему бы просто не использовать '& p [i]'? –

+0

Ну, как я написал его более сложный код, и он в основном работает так, как предполагалось, и здесь дело не в этом. Дело в том, что я не знаю, какой тип указать для std :: get_deleter. – RazzorFlame

+0

Я все еще надеюсь, что вы не используете листинг, такой как 'int (p)' в вашем реальном коде. Это будет *** пробивать почти все 64-битные системы. –

ответ

0

Оказалось, что компилятор не переводил decltype правильно. Я попытался получить deleter сразу после инициализации shared_ptr, и он сработал. Однако тот же самый тип decltype в функции генерировал немного другой тип. Я проверил его в отладчике и сгенерирован результаты:

В конструкторе:

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

В функции:

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

посмотри на конце - это добавляется дополнительные Уста. Мне нужно было изменить его вручную, так что теперь мой код выглядит так:

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; 
Смежные вопросы