2017-01-01 5 views
1

Я хотел бы использовать unique_ptr с моим делетером. Я хотел бы, чтобы мой unique_ptr с моим делетером был полностью совместим с unique_ptr с дефолтом по умолчанию.std :: unique_ptr, изменение пользовательского типа и изменение типа

Я сделал так:

template <typename T> 
struct QObjectDeleteLaterDeletor : 
     public std::default_delete<T> 
{ 
    void operator()(T *p) 
    { 
     p->deleteLater(); 
    } 
}; 

template <typename T, class... Args> 
std::unique_ptr<T> qtMakeUniqueSpecial(Args&&... args) 
{ 
    return std::unique_ptr<T>(
       new T(std::forward<Args>(args)...), 
       QObjectDeleteLaterDeletor<T>()); 
} 

компилируется, но не работает. Мой пользовательский отказ игнорируется и используется по умолчанию, как если бы я вообще не указывал его.

Мне нужно, чтобы все это можно сделать что-то вроде этого:

auto ptr1 = qtMakeUniqueSpecial<MyObject>(); 
std::unique_ptr<MyObject> ptr2; 
ptr2 = std::move(ptr1); 

Пожалуйста, обратите внимание, что теперь даже ptr1.reset() приведет к вызову стандартного Deleter, не мои один.

Возможно ли это?

+1

Но после перемещения тогда 'ptr1' не имеет указателя на данные. Вызов 'reset' на' ptr1' после перехода на «удаление» не имеет смысла. Можете ли вы создать [Минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve) и показать нам? А также, пожалуйста, сообщите нам * как * вы знаете, что ваш делектор не вызван, а по умолчанию. –

+2

Нет. Все, что вы делаете, нарезает ваш причудливый deleter обратно на 'default_delete'. –

+0

Конечно, я вызываю сброс перед движением. Минимальный пример находится в вопросе. –

ответ

1

Вы пытаетесь использовать

namespace std { 
    template<typename T, typename Deleter = default_delete<T> > 
    class unique_ptr; 
} 

, который имеет второй аргумент шаблона Deleter. Если не указывать это значение, оно по умолчанию равно std::default_delete<T>. Ваш код

std::unique_ptr<T>(new T(std::forward<Args>(args)...), 
        QObjectDeleteLaterDeletor<T>()); 

проходит const std::default_delete<T>& к constructor of std::unique_ptr<T>, потому что это то, что ожидает конструктор. После уничтожения (или обратитесь к члену reset()), это будет вызвано.

Обратите внимания, что поведение std::shared_ptr отличается: нет второго аргумента шаблона для Deleter, хотя пользовательские Deleter могут быть предусмотрены на строительстве (это будет необходимо хранить с помощью типа стирания, который можно избежать при std::unique_ptr).

2

В качестве аргумента шаблона необходимо указать QObjectDeleteLaterDeletor; в противном случае std::default_delete будет использоваться в качестве дебетера, который скопирован нарезкой от QObjectDeleteLaterDeletor.

template <typename T, class... Args> 
std::unique_ptr<T, QObjectDeleteLaterDeletor<T>> qtMakeUniqueSpecial(Args&&... args) 
{ 
    return std::unique_ptr<T, QObjectDeleteLaterDeletor<T>> (
       new T(std::forward<Args>(args)...), 
       QObjectDeleteLaterDeletor<T>()); 
} 

Обратите внимание, что вы объявляете ptr2 в std::unique_ptr<MyObject>, то ptr2 уничтожит указатель на std::default_delete. Если вы объявите его соглашением типа с ptr1, как auto ptr2 = std::move(ptr1);, тогда все будет хорошо.

+0

Нет. Это не сработает для меня. Пожалуйста, прочтите мой вопрос. –

+0

Я бы хотел, чтобы мой тип был std :: unique_ptr . Не unique_ptr . –

+0

Это возможно с shared_ptr и кажется невозможным с unique_ptr. –