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 | 18 | 2022-02-01 Jay Berkenbilt <ejb@ql.org> |
| 2 | 19 | |
| 3 | 20 | * Major refactor: all functionality from the qpdf CLI is now | ... | ... |
include/qpdf/PointerHolder.hh
| ... | ... | @@ -22,6 +22,14 @@ |
| 22 | 22 | #ifndef POINTERHOLDER_HH |
| 23 | 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 | 33 | // This class is basically std::shared_ptr but predates that by |
| 26 | 34 | // several years. |
| 27 | 35 | |
| ... | ... | @@ -119,6 +127,12 @@ class PointerHolder |
| 119 | 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 | 136 | // NOTE: The pointer returned by getPointer turns into a pumpkin |
| 123 | 137 | // when the last PointerHolder that contains it disappears. |
| 124 | 138 | T* getPointer() |
| ... | ... | @@ -134,6 +148,12 @@ class PointerHolder |
| 134 | 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 | 157 | T const& operator*() const |
| 138 | 158 | { |
| 139 | 159 | return *this->data->pointer; | ... | ... |
libtests/pointer_holder.cc
| ... | ... | @@ -4,8 +4,6 @@ |
| 4 | 4 | #include <stdlib.h> |
| 5 | 5 | #include <list> |
| 6 | 6 | |
| 7 | -#include <qpdf/QUtil.hh> | |
| 8 | - | |
| 9 | 7 | class Object |
| 10 | 8 | { |
| 11 | 9 | public: |
| ... | ... | @@ -47,13 +45,20 @@ Object::hello() const |
| 47 | 45 | |
| 48 | 46 | typedef PointerHolder<Object> ObjectHolder; |
| 49 | 47 | |
| 50 | -void callHello(ObjectHolder const& oh) | |
| 48 | +void callHello(ObjectHolder& oh) | |
| 51 | 49 | { |
| 52 | 50 | oh.getPointer()->hello(); |
| 53 | 51 | oh->hello(); |
| 54 | 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 | 62 | int main(int argc, char* argv[]) |
| 58 | 63 | { |
| 59 | 64 | std::list<ObjectHolder> ol1; |
| ... | ... | @@ -66,7 +71,7 @@ int main(int argc, char* argv[]) |
| 66 | 71 | std::cout << "oh1 refcount = " << oh1.getRefcount() << std::endl; |
| 67 | 72 | ObjectHolder oh2(oh1); |
| 68 | 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 | 75 | ObjectHolder oh3(new Object); |
| 71 | 76 | ObjectHolder oh4; |
| 72 | 77 | ObjectHolder oh5; |
| ... | ... | @@ -89,12 +94,15 @@ int main(int argc, char* argv[]) |
| 89 | 94 | ol1.push_back(oh3); |
| 90 | 95 | Object* o3 = new Object; |
| 91 | 96 | oh0 = o3; |
| 97 | + PointerHolder<Object const> oh6(new Object()); | |
| 98 | + oh6->hello(); | |
| 92 | 99 | } |
| 93 | 100 | |
| 94 | 101 | ol1.front().getPointer()->hello(); |
| 95 | 102 | ol1.front()->hello(); |
| 96 | 103 | (*ol1.front()).hello(); |
| 97 | 104 | callHello(ol1.front()); |
| 105 | + callHelloWithGet(ol1.front()); | |
| 98 | 106 | ol1.pop_front(); |
| 99 | 107 | std::cout << "array" << std::endl; |
| 100 | 108 | PointerHolder<Object> oarr1_ph(true, new Object[2]); | ... | ... |
libtests/qtest/ph/ph.out
| ... | ... | @@ -10,17 +10,23 @@ destroyed Object, id 2 |
| 10 | 10 | equal okay |
| 11 | 11 | less than okay |
| 12 | 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 | 20 | calling Object::hello for 1 |
| 14 | 21 | calling Object::hello for 1 |
| 15 | 22 | calling Object::hello for 1 |
| 16 | -calling Object::hello const for 1 | |
| 17 | 23 | calling Object::hello const for 1 |
| 18 | 24 | calling Object::hello const for 1 |
| 19 | 25 | array |
| 20 | -created Object, id 4 | |
| 21 | 26 | created Object, id 5 |
| 27 | +created Object, id 6 | |
| 22 | 28 | goodbye |
| 29 | +destroyed Object, id 6 | |
| 23 | 30 | destroyed Object, id 5 |
| 24 | -destroyed Object, id 4 | |
| 25 | 31 | destroyed Object, id 3 |
| 26 | 32 | destroyed Object, id 1 | ... | ... |