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 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