Дедукция Deleter параметра std::unique_ptr

Yaroslav
Yaroslav

В отличае от

  1. auto shBuf = std::shared_ptr<char>(
  2.                 static_cast<char*>(
  3.                         std::calloc(
  4.                                 BUFSIZE, 
  5.                                 sizeof(char)
  6.                         )
  7.                 ),  
  8.                 std::free
  9.         ); 

не компилируется

  1. auto upBuf = std::unique_ptr<char, decltype(deleter)>(
  2.                 static_cast<char*>(
  3.                         std::calloc(
  4.                                 BUFSIZE, 
  5.                                 sizeof(char)
  6.                         )
  7.                 ),
  8.                 std::free
  9.         );

для компиляции необзодим хак вида:

  1. auto deleter = [](char *ptr)
  2.         {              
  3.                 std::free(ptr);
  4.         };             
  5.                        
  6.         auto upBuf = std::unique_ptr<char, decltype(deleter)>(
  7.                 static_cast<char*>(
  8.                         std::calloc(
  9.                                 BUFSIZE,
  10.                                 sizeof(char)
  11.                         )
  12.                 ),     
  13.                 deleter                                                                          
  14.         ); 

Полагаю, что данную неточность стоит пофиксить. 

2
рейтинг
7 комментариев
yndx-antoshkka
Если и исправлять эту проблему, то через deduction giudes. Тогда можно будет писать:

auto upBuf = std::unique_ptr(data, &std::free);

В данный момент в стандарте явно запрещено использовать deduction guide для большинства конструкторов unique_ptr. Лично я на заседании яро боролся за запрет использования deduction guide для конструкторов с одним параметром, т.к. если не указывать deleter то нет возможности различить

auto up_array = std::unique_ptr(new int[100});
auto up_1element = std::unique_ptr(new int);

В итоге немного перестраховались, и пока что запретили deduction guide для всех конструкторов, принимающих pointer.

Если есть желание - помогу с написанием proposal для добавления необходимого deduction guide.

Однако там непросто, и надо продумать все ситуации. Вот параграфы 9-15 [unique.ptr.single.ctor], которые нужно осознать и доработать :

The signature of these constructors depends upon whether D is a reference type. If D is a non-reference
type A, then the signatures are:
unique_ptr(pointer p, const A& d) noexcept;
unique_ptr(pointer p, A&& d) noexcept;

If D is an lvalue reference type A&, then the signatures are:
unique_ptr(pointer p, A& d) noexcept;
unique_ptr(pointer p, A&& d) = delete;

If D is an lvalue reference type const A&, then the signatures are:
unique_ptr(pointer p, const A& d) noexcept;
unique_ptr(pointer p, const A&& d) = delete;

Remarks: If class template argument deduction (16.3.1.8) would select a function template corresponding to either of these constructors, then the program is ill-formed.
yndx-antoshkka
Yaroslav
yndx-antoshkka, ок , разберусь в deduction guide, осмыслю параграфы из стандарта по unique_ptr на выходных. Честно говоря, я в начале пути осознания STL, и никогда не оформлял proposal, но хотелось бы уделить этому время.
Yaroslav
Antervis
yndx-antoshkka, но мы же можем определить deduction guide для конструктора с двумя аргументами, например так:

template <class T, class Deleter, typename = decltype(declval<Deleter>()(declval<T*>()))>
unique_ptr(T*, Deleter &&) -> unique_ptr<T,Deleter>;
Antervis
Andrey Davydov
Antervis, в таком случае unique_ptr(new int[1], default_delete<int[]>) выведется в unique_ptr<int, default_delete[]> вместо unique_ptr<int[], default_delete[]>, а unique_ptr(malloc(1), free) выведется в unique_ptr<void, void(void*) noexcept> вместо unique_ptr<void, void(&)(void*) noexcept>.
Andrey Davydov
Andrey Davydov
yndx-antoshkka, мне, кажется, удалось создать рабочие deduction guides, ценой введения дополнительного customization point'а `deleter_applicable_to_array`: github.com/AndreyG/unique-ptr-deduction-guides Буду рад любым комментариям от всех заинтересованных.
Andrey Davydov
yndx-antoshkka
Andrey Davydov, надо постараться максимально упростить эти guides.

* Как мне кажется, новая customization point, чисто для deduction guides, не пройдёт. Так что стоит забить на случай unique_ptr<int, default_delete[]> и не мучаться. Ну не будет у пользователя operator[] b kflyj - пусть пользуется make_unique для этого случая.
* Вот тут есть риск получить unique_ptr<int, some_deleter&>, что скорее всего не то, что хотел пользователь github.com/AndreyG/unique-ptr-deduction-guides/blob/master/deduction_guides.h#L56
yndx-antoshkka
Andrey Davydov
yndx-antoshkka,
> Как мне кажется, новая customization point, чисто для deduction guides, не пройдёт.
Ок, а если определить у default_delete<T[]> typedef `applicable_to_array` по аналогии c less<void>::is_transparent? Это же будет совсем не инвазивно.
> Вот тут есть риск получить unique_ptr<int, some_deleter&>
вроде не должно быть, я же проверяю is_object_v<D>; is_object_v<some_deleter&> == false.
Andrey Davydov
Другие идеи
Группа создана, чтобы собирать предложения к стандарту C++, организовывать их внутренние обсуждения, помогать готовить их для отправки в комитет и защищать на общих собраниях в рабочей группе по С++ Международной организации по стандартизации (ISO).