From f727bc94432905d79af23cf0aef14854965da2cd Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Fri, 4 Feb 2022 09:46:55 -0500 Subject: [PATCH] PointerHolder: add get() and use_count() for forward compatibility PointerHolder will be replaced with shared_ptr, so let people start moving. --- ChangeLog | 17 +++++++++++++++++ include/qpdf/PointerHolder.hh | 20 ++++++++++++++++++++ libtests/pointer_holder.cc | 16 ++++++++++++---- libtests/qtest/ph/ph.out | 12 +++++++++--- 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 337b197d..77c63419 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2022-02-04 Jay Berkenbilt + + * PointerHolder: add a get() method and a use_count() method for + compatibility with std::shared_ptr. In qpdf 11, qpdf's APIs will + switch to using std::shared_ptr instead of PointerHolder, though + there will be a PointerHolder class with a backward-compatible + API. To ease the transition, we are adding get() now with the same + semantics as std::shared_ptr's get. Note that there is a + difference in behavior: const PointerHolder has always behaved + incorrectly. const PointerHolder objects only returned const + pointers. This is wrong. If you want a const pointer, use + PointerHolder. A const PointerHolder just shouldn't allow + its pointer to be reassigned. The new get() method behaves + correctly in that calling get() on a const PointerHolder to a + non-const pointer returns a non-const pointer. This is the way + regular pointers behave. + 2022-02-01 Jay Berkenbilt * Major refactor: all functionality from the qpdf CLI is now diff --git a/include/qpdf/PointerHolder.hh b/include/qpdf/PointerHolder.hh index a85df8bb..bc60f7f0 100644 --- a/include/qpdf/PointerHolder.hh +++ b/include/qpdf/PointerHolder.hh @@ -22,6 +22,14 @@ #ifndef POINTERHOLDER_HH #define POINTERHOLDER_HH +// In qpdf 11, PointerHolder will be derived from std::shared_ptr and +// will also include a fix to incorrect semantics of const +// PointerHolder objects. PointerHolder only allows a const +// PointerHolder to return a const pointer. This is wrong. Use a +// PointerHolder for that. A const PointerHolder should just +// not allow you to change what it points to. This is consistent with +// how regular pointers and standard library shared pointers work. + // This class is basically std::shared_ptr but predates that by // several years. @@ -119,6 +127,12 @@ class PointerHolder return this->data->pointer < rhs.data->pointer; } + // get() is for interface compatibility with std::shared_ptr + T* get() const + { + return this->data->pointer; + } + // NOTE: The pointer returned by getPointer turns into a pumpkin // when the last PointerHolder that contains it disappears. T* getPointer() @@ -134,6 +148,12 @@ class PointerHolder return this->data->refcount; } + // use_count() is for compatibility with std::shared_ptr + long use_count() + { + return static_cast(this->data->refcount); + } + T const& operator*() const { return *this->data->pointer; diff --git a/libtests/pointer_holder.cc b/libtests/pointer_holder.cc index 469bfc21..913449e4 100644 --- a/libtests/pointer_holder.cc +++ b/libtests/pointer_holder.cc @@ -4,8 +4,6 @@ #include #include -#include - class Object { public: @@ -47,13 +45,20 @@ Object::hello() const typedef PointerHolder ObjectHolder; -void callHello(ObjectHolder const& oh) +void callHello(ObjectHolder& oh) { oh.getPointer()->hello(); oh->hello(); (*oh).hello(); } +void callHelloWithGet(ObjectHolder const& oh) +{ + oh.get()->hello(); + oh->hello(); + (*oh).hello(); +} + int main(int argc, char* argv[]) { std::list ol1; @@ -66,7 +71,7 @@ int main(int argc, char* argv[]) std::cout << "oh1 refcount = " << oh1.getRefcount() << std::endl; ObjectHolder oh2(oh1); std::cout << "oh1 refcount = " << oh1.getRefcount() << std::endl; - std::cout << "oh2 refcount = " << oh2.getRefcount() << std::endl; + std::cout << "oh2 refcount = " << oh2.use_count() << std::endl; ObjectHolder oh3(new Object); ObjectHolder oh4; ObjectHolder oh5; @@ -89,12 +94,15 @@ int main(int argc, char* argv[]) ol1.push_back(oh3); Object* o3 = new Object; oh0 = o3; + PointerHolder oh6(new Object()); + oh6->hello(); } ol1.front().getPointer()->hello(); ol1.front()->hello(); (*ol1.front()).hello(); callHello(ol1.front()); + callHelloWithGet(ol1.front()); ol1.pop_front(); std::cout << "array" << std::endl; PointerHolder oarr1_ph(true, new Object[2]); diff --git a/libtests/qtest/ph/ph.out b/libtests/qtest/ph/ph.out index 5d249712..a7efe1bb 100644 --- a/libtests/qtest/ph/ph.out +++ b/libtests/qtest/ph/ph.out @@ -10,17 +10,23 @@ destroyed Object, id 2 equal okay less than okay created Object, id 3 +created Object, id 4 +calling Object::hello const for 4 +destroyed Object, id 4 +calling Object::hello for 1 +calling Object::hello for 1 +calling Object::hello for 1 +calling Object::hello for 1 calling Object::hello for 1 calling Object::hello for 1 calling Object::hello for 1 -calling Object::hello const for 1 calling Object::hello const for 1 calling Object::hello const for 1 array -created Object, id 4 created Object, id 5 +created Object, id 6 goodbye +destroyed Object, id 6 destroyed Object, id 5 -destroyed Object, id 4 destroyed Object, id 3 destroyed Object, id 1