Добавить в стандартную библиотеку intrusive_ptr
Перенос предложения: голоса +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_;
};
yndx-antoshkka, 30 мая 2018, 19:23 Идея мне нравится. Есть придирки:
- operator!() не нужен
- downcast() и upcast() надо заменить на *_pointer_cast
- Возможно что будет лучше, если intrusive_ptr_release и intrusive_ptr_add_ref будут принимать ссылки, а не указатели (это упростит жизнь пользователям, им не придётся гадать "А может ли мне прийти nullptr?").
- Конструкторы должны быть от шаблонных параметров, а не от T. Это спасёт например от implicit deduction guides (которые тут могут навредить). См http://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
- operator* не должен быть noexcept (разыменовывание nullptr ведёт к UB, при UB noexcept не пишется)
Отдельно стоит расписать, почему свободные функции используются для кастомизации (а не какой-то шаблонный параметр). И добавить требование, что функции 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), а не требования.
тоже жду не до ждусь когда бустоый intrusive_ptr перенесут в std::