2015-04-15 3 views
11

Скажем, я хочу использовать пользовательский Deleter с unique_ptr:Почему unique_ptr не может вывести тип делетера?

void custom_deleter(int* obj) 
{ 
    delete obj; 
} 

Почему я должен написать это:

std::unique_ptr<int, void(*)(int*)> x(new int, custom_deleter); 

вместо этого:

std::unique_ptr<int> x(new int, custom_deleter); //does not compile 

?

Нельзя ли определить тип делетера?

+1

Связанные: http://stackoverflow.com/questions/21355037/why-does-unique-ptr-take-two-template-parameters-when-shared-ptr-only-takes-one – 0x499602D2

+4

Шаблонные классы не вывести параметры шаблона. Только функции шаблона. –

+3

Интересно, почему 'std :: make_unique' не имеет перегрузки, в которой вы можете указать дебетер. Таким образом, вы можете определить тип делетира. – vsoftco

ответ

6

Для unique_ptr, то Deleter является частью типа:

template < 
    class T, 
    class Deleter = std::default_delete<T> 
> class unique_ptr; 

Таким образом, когда вы построения объекта, необходимо указать его тип. Линия вы пишете:

std::unique_ptr<int> x(new int, custom_deleter); 

эквивалентно:

std::unique_ptr<int, std::default_delete<int> > x(new int, custom_deleter); 

И вы не можете построить std::default_delete<int> из custom_deleter.

Единственного способ Infer типа Deleter является использование шаблона вычета на ту часть тоже:

template <typename T, typename Deleter> 
std::unique_ptr<T, Deleter> make_unique_ptr(T* ptr, Deleter deleter) { 
    return std::unique_ptr<T, Deleter>(ptr, deleter); 
} 
+0

Это именно то, что я сделал бы для 'std :: make_unique', не вижу причин, почему это не реализовано так. – vsoftco

+2

@vsoftco [скопировано сверху] Как это будет работать? Он должен принять пакет аргументов, чтобы построить T. Как бы вы различали, какой из Args ... является Deleter? – Barry

+0

, возможно, с помощью 'std :: piecewise_construct' /' std :: forward_as_tuple' – vsoftco

3

Он не может вывести тип Deleter, потому что unique_ptr по умолчанию не имеет состояния, затрачиваемое на deleter: дефолт по умолчанию является апатридом.

В вашем случае, делетеру требуется состояние указателя, поэтому он не может «поместиться» в состояние std::unique_ptr (это всего лишь указатель на T).

Это делает unique_ptr легкой, почти бесплатной заменой для владеющего указателя.

Deductin может быть выполнен, но он должен будет изменить тип получаемого unique_ptr.

Для сравнения, shared_ptr всегда имеет емкость состояний для дебетера, два разных счетчика атомов и указатель на значение. Это более тяжелый вес, а не дешевая замена указателя.

Смежные вопросы