cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
89 stars 0 forks source link

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

Open apolukhin opened 3 years ago

apolukhin commented 3 years ago

Перенос предложения: голоса +2, -1 Автор идеи: Yaroslav

Это моя первая заметка по языку С++, не судите строго. Недавно обнаружил некоторое различие в дедукции std::shared_ptr и std::unique_ptr

В отличае от

    auto shBuf = std::shared_ptr<char>(
                    static_cast<char*>(
                            std::calloc(
                                    BUFSIZE, 
                                    sizeof(char)
                            )
                    ),  
                    std::free
            ); 

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

    auto upBuf = std::unique_ptr<char, decltype(deleter)>(
                    static_cast<char*>(
                            std::calloc(
                                    BUFSIZE, 
                                    sizeof(char)
                            )
                    ),
                    std::free
            );

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

    auto deleter = [](char *ptr)
            {              
                    std::free(ptr);
            };             

            auto upBuf = std::unique_ptr<char, decltype(deleter)>(
                    static_cast<char*>(
                            std::calloc(
                                    BUFSIZE,
                                    sizeof(char)
                            )
                    ),     
                    deleter                                                                          
            ); 

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

apolukhin commented 3 years ago

yndx-antoshkka, 9 августа 2017, 13:34 Если и исправлять эту проблему, то через 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.

Yaroslav, 10 августа 2017, 15:46 yndx-antoshkka, ок , разберусь в deduction guide, осмыслю параграфы из стандарта по unique_ptr на выходных. Честно говоря, я в начале пути осознания STL, и никогда не оформлял proposal, но хотелось бы уделить этому время.

Antervis, 11 августа 2017, 10:29 yndx-antoshkka, но мы же можем определить deduction guide для конструктора с двумя аргументами, например так:

template <class T, class Deleter, typename = decltype(declval<Deleter>()(declval<T*>()))>
unique_ptr(T*, Deleter &&) -> unique_ptr<T,Deleter>;

Andrey Davydov, 11 августа 2017, 13:27 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, 11 августа 2017, 14:06 yndx-antoshkka, мне, кажется, удалось создать рабочие deduction guides, ценой введения дополнительного customization point'а deleter_applicable_to_array: https://github.com/AndreyG/unique-ptr-deduction-guides Буду рад любым комментариям от всех заинтересованных.

yndx-antoshkka, 11 августа 2017, 14:43 Andrey Davydov, надо постараться максимально упростить эти guides.

Andrey Davydov, 11 августа 2017, 15:04 yndx-antoshkka,

Как мне кажется, новая customization point, чисто для deduction guides, не пройдёт.

Ок, а если определить у default_delete<T[]> typedef applicable_to_array по аналогии c less::is_transparent? Это же будет совсем не инвазивно.

Вот тут есть риск получить unique_ptr<int, some_deleter&>

вроде не должно быть, я же проверяю is_object_v; is_object_v<some_deleter&> == false.