Commit f727bc94432905d79af23cf0aef14854965da2cd

Authored by Jay Berkenbilt
1 parent f76191f0

PointerHolder: add get() and use_count() for forward compatibility

PointerHolder will be replaced with shared_ptr, so let people start
moving.
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
... ...