Commit f727bc94432905d79af23cf0aef14854965da2cd
1 parent
f76191f0
PointerHolder: add get() and use_count() for forward compatibility
PointerHolder will be replaced with shared_ptr, so let people start moving.
Showing
4 changed files
with
58 additions
and
7 deletions
ChangeLog
| 1 | +2022-02-04 Jay Berkenbilt <ejb@ql.org> | ||
| 2 | + | ||
| 3 | + * PointerHolder: add a get() method and a use_count() method for | ||
| 4 | + compatibility with std::shared_ptr. In qpdf 11, qpdf's APIs will | ||
| 5 | + switch to using std::shared_ptr instead of PointerHolder, though | ||
| 6 | + there will be a PointerHolder class with a backward-compatible | ||
| 7 | + API. To ease the transition, we are adding get() now with the same | ||
| 8 | + semantics as std::shared_ptr's get. Note that there is a | ||
| 9 | + difference in behavior: const PointerHolder has always behaved | ||
| 10 | + incorrectly. const PointerHolder objects only returned const | ||
| 11 | + pointers. This is wrong. If you want a const pointer, use | ||
| 12 | + PointerHolder<T const>. A const PointerHolder just shouldn't allow | ||
| 13 | + its pointer to be reassigned. The new get() method behaves | ||
| 14 | + correctly in that calling get() on a const PointerHolder to a | ||
| 15 | + non-const pointer returns a non-const pointer. This is the way | ||
| 16 | + regular pointers behave. | ||
| 17 | + | ||
| 1 | 2022-02-01 Jay Berkenbilt <ejb@ql.org> | 18 | 2022-02-01 Jay Berkenbilt <ejb@ql.org> |
| 2 | 19 | ||
| 3 | * Major refactor: all functionality from the qpdf CLI is now | 20 | * Major refactor: all functionality from the qpdf CLI is now |
include/qpdf/PointerHolder.hh
| @@ -22,6 +22,14 @@ | @@ -22,6 +22,14 @@ | ||
| 22 | #ifndef POINTERHOLDER_HH | 22 | #ifndef POINTERHOLDER_HH |
| 23 | #define POINTERHOLDER_HH | 23 | #define POINTERHOLDER_HH |
| 24 | 24 | ||
| 25 | +// In qpdf 11, PointerHolder will be derived from std::shared_ptr and | ||
| 26 | +// will also include a fix to incorrect semantics of const | ||
| 27 | +// PointerHolder objects. PointerHolder only allows a const | ||
| 28 | +// PointerHolder to return a const pointer. This is wrong. Use a | ||
| 29 | +// PointerHolder<const T> for that. A const PointerHolder should just | ||
| 30 | +// not allow you to change what it points to. This is consistent with | ||
| 31 | +// how regular pointers and standard library shared pointers work. | ||
| 32 | + | ||
| 25 | // This class is basically std::shared_ptr but predates that by | 33 | // This class is basically std::shared_ptr but predates that by |
| 26 | // several years. | 34 | // several years. |
| 27 | 35 | ||
| @@ -119,6 +127,12 @@ class PointerHolder | @@ -119,6 +127,12 @@ class PointerHolder | ||
| 119 | return this->data->pointer < rhs.data->pointer; | 127 | return this->data->pointer < rhs.data->pointer; |
| 120 | } | 128 | } |
| 121 | 129 | ||
| 130 | + // get() is for interface compatibility with std::shared_ptr | ||
| 131 | + T* get() const | ||
| 132 | + { | ||
| 133 | + return this->data->pointer; | ||
| 134 | + } | ||
| 135 | + | ||
| 122 | // NOTE: The pointer returned by getPointer turns into a pumpkin | 136 | // NOTE: The pointer returned by getPointer turns into a pumpkin |
| 123 | // when the last PointerHolder that contains it disappears. | 137 | // when the last PointerHolder that contains it disappears. |
| 124 | T* getPointer() | 138 | T* getPointer() |
| @@ -134,6 +148,12 @@ class PointerHolder | @@ -134,6 +148,12 @@ class PointerHolder | ||
| 134 | return this->data->refcount; | 148 | return this->data->refcount; |
| 135 | } | 149 | } |
| 136 | 150 | ||
| 151 | + // use_count() is for compatibility with std::shared_ptr | ||
| 152 | + long use_count() | ||
| 153 | + { | ||
| 154 | + return static_cast<long>(this->data->refcount); | ||
| 155 | + } | ||
| 156 | + | ||
| 137 | T const& operator*() const | 157 | T const& operator*() const |
| 138 | { | 158 | { |
| 139 | return *this->data->pointer; | 159 | return *this->data->pointer; |
libtests/pointer_holder.cc
| @@ -4,8 +4,6 @@ | @@ -4,8 +4,6 @@ | ||
| 4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
| 5 | #include <list> | 5 | #include <list> |
| 6 | 6 | ||
| 7 | -#include <qpdf/QUtil.hh> | ||
| 8 | - | ||
| 9 | class Object | 7 | class Object |
| 10 | { | 8 | { |
| 11 | public: | 9 | public: |
| @@ -47,13 +45,20 @@ Object::hello() const | @@ -47,13 +45,20 @@ Object::hello() const | ||
| 47 | 45 | ||
| 48 | typedef PointerHolder<Object> ObjectHolder; | 46 | typedef PointerHolder<Object> ObjectHolder; |
| 49 | 47 | ||
| 50 | -void callHello(ObjectHolder const& oh) | 48 | +void callHello(ObjectHolder& oh) |
| 51 | { | 49 | { |
| 52 | oh.getPointer()->hello(); | 50 | oh.getPointer()->hello(); |
| 53 | oh->hello(); | 51 | oh->hello(); |
| 54 | (*oh).hello(); | 52 | (*oh).hello(); |
| 55 | } | 53 | } |
| 56 | 54 | ||
| 55 | +void callHelloWithGet(ObjectHolder const& oh) | ||
| 56 | +{ | ||
| 57 | + oh.get()->hello(); | ||
| 58 | + oh->hello(); | ||
| 59 | + (*oh).hello(); | ||
| 60 | +} | ||
| 61 | + | ||
| 57 | int main(int argc, char* argv[]) | 62 | int main(int argc, char* argv[]) |
| 58 | { | 63 | { |
| 59 | std::list<ObjectHolder> ol1; | 64 | std::list<ObjectHolder> ol1; |
| @@ -66,7 +71,7 @@ int main(int argc, char* argv[]) | @@ -66,7 +71,7 @@ int main(int argc, char* argv[]) | ||
| 66 | std::cout << "oh1 refcount = " << oh1.getRefcount() << std::endl; | 71 | std::cout << "oh1 refcount = " << oh1.getRefcount() << std::endl; |
| 67 | ObjectHolder oh2(oh1); | 72 | ObjectHolder oh2(oh1); |
| 68 | std::cout << "oh1 refcount = " << oh1.getRefcount() << std::endl; | 73 | std::cout << "oh1 refcount = " << oh1.getRefcount() << std::endl; |
| 69 | - std::cout << "oh2 refcount = " << oh2.getRefcount() << std::endl; | 74 | + std::cout << "oh2 refcount = " << oh2.use_count() << std::endl; |
| 70 | ObjectHolder oh3(new Object); | 75 | ObjectHolder oh3(new Object); |
| 71 | ObjectHolder oh4; | 76 | ObjectHolder oh4; |
| 72 | ObjectHolder oh5; | 77 | ObjectHolder oh5; |
| @@ -89,12 +94,15 @@ int main(int argc, char* argv[]) | @@ -89,12 +94,15 @@ int main(int argc, char* argv[]) | ||
| 89 | ol1.push_back(oh3); | 94 | ol1.push_back(oh3); |
| 90 | Object* o3 = new Object; | 95 | Object* o3 = new Object; |
| 91 | oh0 = o3; | 96 | oh0 = o3; |
| 97 | + PointerHolder<Object const> oh6(new Object()); | ||
| 98 | + oh6->hello(); | ||
| 92 | } | 99 | } |
| 93 | 100 | ||
| 94 | ol1.front().getPointer()->hello(); | 101 | ol1.front().getPointer()->hello(); |
| 95 | ol1.front()->hello(); | 102 | ol1.front()->hello(); |
| 96 | (*ol1.front()).hello(); | 103 | (*ol1.front()).hello(); |
| 97 | callHello(ol1.front()); | 104 | callHello(ol1.front()); |
| 105 | + callHelloWithGet(ol1.front()); | ||
| 98 | ol1.pop_front(); | 106 | ol1.pop_front(); |
| 99 | std::cout << "array" << std::endl; | 107 | std::cout << "array" << std::endl; |
| 100 | PointerHolder<Object> oarr1_ph(true, new Object[2]); | 108 | PointerHolder<Object> oarr1_ph(true, new Object[2]); |
libtests/qtest/ph/ph.out
| @@ -10,17 +10,23 @@ destroyed Object, id 2 | @@ -10,17 +10,23 @@ destroyed Object, id 2 | ||
| 10 | equal okay | 10 | equal okay |
| 11 | less than okay | 11 | less than okay |
| 12 | created Object, id 3 | 12 | created Object, id 3 |
| 13 | +created Object, id 4 | ||
| 14 | +calling Object::hello const for 4 | ||
| 15 | +destroyed Object, id 4 | ||
| 16 | +calling Object::hello for 1 | ||
| 17 | +calling Object::hello for 1 | ||
| 18 | +calling Object::hello for 1 | ||
| 19 | +calling Object::hello for 1 | ||
| 13 | calling Object::hello for 1 | 20 | calling Object::hello for 1 |
| 14 | calling Object::hello for 1 | 21 | calling Object::hello for 1 |
| 15 | calling Object::hello for 1 | 22 | calling Object::hello for 1 |
| 16 | -calling Object::hello const for 1 | ||
| 17 | calling Object::hello const for 1 | 23 | calling Object::hello const for 1 |
| 18 | calling Object::hello const for 1 | 24 | calling Object::hello const for 1 |
| 19 | array | 25 | array |
| 20 | -created Object, id 4 | ||
| 21 | created Object, id 5 | 26 | created Object, id 5 |
| 27 | +created Object, id 6 | ||
| 22 | goodbye | 28 | goodbye |
| 29 | +destroyed Object, id 6 | ||
| 23 | destroyed Object, id 5 | 30 | destroyed Object, id 5 |
| 24 | -destroyed Object, id 4 | ||
| 25 | destroyed Object, id 3 | 31 | destroyed Object, id 3 |
| 26 | destroyed Object, id 1 | 32 | destroyed Object, id 1 |