cpp-ru / ideas

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

Добавить в стандартную библиотеку intrusive_ptr #307

Open apolukhin opened 3 years ago

apolukhin commented 3 years ago

Перенос предложения: голоса +10, -0 Автор идеи: kotbegemot @kotbegemot

Устал от того что в стандартной библиотеки не какой альтернативе shared_ptr предлагаю добавить intrusive_ptr. https://github.com/kotbegemot/intrusive_ptr принимаю предложения и комментарии.

template<class T>
    class intrusive_ptr {
    public:
        using pointer = T*;
        using const_pointer = const T*;
        using element_type = T;
        using reference = T&;
        using const_reference = const T&;

        constexpr intrusive_ptr() noexcept : ptr_(nullptr) {}

        intrusive_ptr(pointer raw_ptr, bool add_ref = true) noexcept {
            set_ptr(raw_ptr, add_ref);
        }

        intrusive_ptr(intrusive_ptr &&other) noexcept : ptr_(other.detach()) {}

        intrusive_ptr(const intrusive_ptr &other) noexcept {
            set_ptr(other.get(), true);
        }

        template<class Y>
        intrusive_ptr(intrusive_ptr<Y> other) : ptr_(other.detach()) {
            static_assert(std::is_convertible<Y *, T *>::value,
                          "Y* is not assignable to T*");
        }

        intrusive_ptr &operator=(pointer ptr) noexcept {
            reset(ptr);
            return *this;
        }

        intrusive_ptr &operator=(intrusive_ptr other) noexcept {
            swap(other);
            return *this;
        }

        ~intrusive_ptr() {
            if (ptr_) {
                intrusive_ptr_release(ptr_);
            }
        }

        pointer detach() noexcept {
            auto result = ptr_;
            if (result) {
                ptr_ = nullptr;
            }
            return result;
        }

        pointer release() noexcept {
            return detach();
        }

        void reset(pointer new_value = nullptr, bool add_ref = true) noexcept {
            auto old = ptr_;
            set_ptr(new_value, add_ref);
            if (old) {
                intrusive_ptr_release(old);
            }
        }

        pointer get() const noexcept {
            return ptr_;
        }

        pointer operator->() const noexcept {
            return ptr_;
        }

        reference operator*() const noexcept {
            return *ptr_;
        }

        bool operator!() const noexcept {
            return ptr_ == nullptr;
        }

        explicit operator bool() const noexcept {
            return ptr_ != nullptr;
        }

        void swap(intrusive_ptr &other) noexcept {
            std::swap(ptr_, other.ptr_);
        }

        template<class C>
        intrusive_ptr<C> downcast() const noexcept {
            return (ptr_) ? dynamic_cast<C *>(get()) : nullptr;
        }

        template<class C>
        intrusive_ptr<C> upcast() const noexcept {
            return (ptr_) ? static_cast<C *>(get()) : nullptr;
        }

    private:
        inline void set_ptr(pointer raw_ptr, bool add_ref) noexcept {
            ptr_ = raw_ptr;
            if (raw_ptr && add_ref) {
                intrusive_ptr_add_ref(raw_ptr);
            }
        }

        pointer ptr_;
};
apolukhin commented 3 years ago

yndx-antoshkka, 30 мая 2018, 19:23 Идея мне нравится. Есть придирки:

Отдельно стоит расписать, почему свободные функции используются для кастомизации (а не какой-то шаблонный параметр). И добавить требование, что функции intrusive_ptr_release и intrusive_ptr_add_ref должны быть noexcept, иначе - ошибка компиляции.

languagelawyer, 1 июня 2018, 11:21

при UB noexcept не пишется

Откуда такое правило?

yndx-antoshkka, 1 июня 2018, 13:43 в некоторых компиляторах есть различные флаги, позволяющие в случае UB например кидать исключение. Если помечать функции с UB как noexcept, то вместо исключения будет вызван std::terminate.

languagelawyer, 1 июня 2018, 14:03 yndx-antoshkka, noexcept у std::shared_ptr::operator* - это дефект?

yndx-antoshkka, 1 июня 2018, 14:43 Обновлено 1 июня 2018, 14:03

languagelawyer, да. К несчастью не устранимый https://cplusplus.github.io/LWG/issue2337

Для консистентности думают сделать правки в другие части стандартной библиотеки https://cplusplus.github.io/LWG/issue2762 но пока что их не приняли. Так что лучше пока не добавлять noexcept по аналогии с большинством operator*()

neondev9, 31 мая 2018, 15:16 поддерживаю

Виктор Губин, 18 марта 2019, 18:52 Класс малость по-сложенее будет. Нехватает операторов сравнения, проверок на соместимость типов (p_enable_if_convertible) и xxx_pointer_cast функций.

Alexander Enaldiev, 18 марта 2020, 17:36 Да, добавить было бы неплохо.

К сожалению, предложена частная реализация (+ в камментах ссылка на yet another из boost), а не требования.