diff options
author | Jay Berkenbilt <ejb@ql.org> | 2022-04-09 20:32:23 +0200 |
---|---|---|
committer | Jay Berkenbilt <ejb@ql.org> | 2022-04-09 23:33:29 +0200 |
commit | ae819b5318bf0a0a21b80d6269ef73ed8123d5d6 (patch) | |
tree | dfebb1199f18c992183576b7a7d9183dc88f8346 /include | |
parent | ec219100668357e46cc8640386e2332379956b7c (diff) | |
download | qpdf-ae819b5318bf0a0a21b80d6269ef73ed8123d5d6.tar.zst |
Rewrite PointerHolder as derived from std::shared_ptr
Diffstat (limited to 'include')
-rw-r--r-- | include/qpdf/PointerHolder.hh | 204 |
1 files changed, 45 insertions, 159 deletions
diff --git a/include/qpdf/PointerHolder.hh b/include/qpdf/PointerHolder.hh index fb186778..b51ca7ba 100644 --- a/include/qpdf/PointerHolder.hh +++ b/include/qpdf/PointerHolder.hh @@ -39,6 +39,8 @@ # define POINTERHOLDER_TRANSITION 0 #endif // !defined(POINTERHOLDER_TRANSITION) +#if POINTERHOLDER_TRANSITION < 4 + // *** WHAT IS HAPPENING *** // In qpdf 11, PointerHolder will be replaced with std::shared_ptr @@ -140,211 +142,94 @@ // written code. If you are relying on the incorrect behavior, use // PointerHolder<T const> instead. -// OLD DOCUMENTATION - -// This class is basically std::shared_ptr but predates that by -// several years. - -// This class expects to be initialized with a dynamically allocated -// object pointer. It keeps a reference count and deletes this once -// the reference count goes to zero. PointerHolder objects are -// explicitly safe for use in STL containers. - -// It is very important that a client who pulls the pointer out of -// this holder does not let the holder go out of scope until it is -// finished with the pointer. It is also important that exactly one -// instance of this object ever gets initialized with a given pointer. -// Otherwise, the pointer will be deleted twice, and before that, some -// objects will be left with a pointer to a deleted object. In other -// words, the only legitimate way for two PointerHolder objects to -// contain the same pointer is for one to be a copy of the other. -// Copy and assignment semantics are well-defined and essentially -// allow you to use PointerHolder as a means to get pass-by-reference -// semantics in a pass-by-value environment without having to worry -// about memory management details. - -// Comparison (== and <) are defined and operate on the internally -// stored pointers, not on the data. This makes it possible to store -// PointerHolder objects in sorted lists or to find them in STL -// containers just as one would be able to store pointers. Comparing -// the underlying pointers provides a well-defined, if not -// particularly meaningful, ordering. - -#include <cstddef> +# include <cstddef> +# include <memory> template <class T> -class PointerHolder +class PointerHolder: public std::shared_ptr<T> { - private: - class Data - { - public: - Data(T* pointer, bool array) : - pointer(pointer), - array(array), - refcount(0) - { - } - ~Data() - { - if (array) { - delete[] this->pointer; - } else { - delete this->pointer; - } - } - T* pointer; - bool array; - int refcount; - - private: - Data(Data const&) = delete; - Data& operator=(Data const&) = delete; - }; - public: -#if POINTERHOLDER_TRANSITION >= 1 - explicit -#endif // POINTERHOLDER_TRANSITION >= 1 - PointerHolder(T* pointer = 0) - { - this->init(new Data(pointer, false)); - } - // Special constructor indicating to free memory with delete [] - // instead of delete - PointerHolder(bool, T* pointer) - { - this->init(new Data(pointer, true)); - } - PointerHolder(PointerHolder const& rhs) - { - this->copy(rhs); - } - PointerHolder& - operator=(PointerHolder const& rhs) - { - if (this != &rhs) { - this->destroy(); - this->copy(rhs); - } - return *this; - } - PointerHolder& - operator=(decltype(nullptr)) +# if POINTERHOLDER_TRANSITION >= 3 + [[deprecated("use std::shared_ptr<T> instead")]] +# endif // POINTERHOLDER_TRANSITION >= 3 + PointerHolder(std::shared_ptr<T> other) : + std::shared_ptr<T>(other) { - this->operator=(PointerHolder<T>()); - return *this; } - ~PointerHolder() - { - this->destroy(); - } - bool - operator==(PointerHolder const& rhs) const - { - return this->data->pointer == rhs.data->pointer; - } - bool - operator==(decltype(nullptr)) const +# if POINTERHOLDER_TRANSITION >= 3 + [[deprecated("use std::shared_ptr<T> instead")]] +# if POINTERHOLDER_TRANSITION >= 1 + explicit +# endif // POINTERHOLDER_TRANSITION >= 1 +# endif // POINTERHOLDER_TRANSITION >= 3 + PointerHolder(T* pointer = 0) : + std::shared_ptr<T>(pointer) { - return this->data->pointer == nullptr; } - bool - operator<(PointerHolder const& rhs) const + // Create a shared pointer to an array +# if POINTERHOLDER_TRANSITION >= 3 + [[deprecated("use std::shared_ptr<T> instead")]] +# endif // POINTERHOLDER_TRANSITION >= 3 + PointerHolder(bool, T* pointer) : + std::shared_ptr<T>(pointer, std::default_delete<T[]>()) { - return this->data->pointer < rhs.data->pointer; } - // get() is for interface compatibility with std::shared_ptr - T* - get() const - { - return this->data->pointer; - } + virtual ~PointerHolder() = default; - // NOTE: The pointer returned by getPointer turns into a pumpkin - // when the last PointerHolder that contains it disappears. -#if POINTERHOLDER_TRANSITION >= 2 +# if POINTERHOLDER_TRANSITION >= 2 [[deprecated("use PointerHolder<T>::get() instead of getPointer()")]] -#endif // POINTERHOLDER_TRANSITION >= 2 +# endif // POINTERHOLDER_TRANSITION >= 2 T* getPointer() { - return this->data->pointer; + return this->get(); } -#if POINTERHOLDER_TRANSITION >= 2 +# if POINTERHOLDER_TRANSITION >= 2 [[deprecated("use PointerHolder<T>::get() instead of getPointer()")]] -#endif // POINTERHOLDER_TRANSITION >= 2 +# endif // POINTERHOLDER_TRANSITION >= 2 T const* getPointer() const { - return this->data->pointer; + return this->get(); } -#if POINTERHOLDER_TRANSITION >= 2 - [[deprecated("use use_count() instead of getRefcount()")]] -#endif // POINTERHOLDER_TRANSITION >= 2 + +# if POINTERHOLDER_TRANSITION >= 2 + [[deprecated("use PointerHolder<T>::get() instead of getPointer()")]] +# endif // POINTERHOLDER_TRANSITION >= 2 int getRefcount() const { - return this->data->refcount; + return static_cast<int>(this->use_count()); } - // use_count() is for compatibility with std::shared_ptr - long - use_count() + PointerHolder& + operator=(decltype(nullptr)) { - return static_cast<long>(this->data->refcount); + std::shared_ptr<T>::operator=(nullptr); + return *this; } - T const& operator*() const { - return *this->data->pointer; + return *(this->get()); } T& operator*() { - return *this->data->pointer; + return *(this->get()); } T const* operator->() const { - return this->data->pointer; + return this->get(); } T* operator->() { - return this->data->pointer; + return this->get(); } - - private: - void - init(Data* data) - { - this->data = data; - ++this->data->refcount; - } - void - copy(PointerHolder const& rhs) - { - this->init(rhs.data); - } - void - destroy() - { - bool gone = false; - { - if (--this->data->refcount == 0) { - gone = true; - } - } - if (gone) { - delete this->data; - } - } - - Data* data; }; template <typename T, typename... _Args> @@ -361,4 +246,5 @@ make_array_pointer_holder(size_t n) return PointerHolder<T>(true, new T[n]); } +#endif // POINTERHOLDER_TRANSITION < 4 #endif // POINTERHOLDER_HH |