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

PointerHolder will be replaced with shared_ptr, so let people start
moving.
This commit is contained in:
Jay Berkenbilt 2022-02-04 09:46:55 -05:00
parent f76191f0c2
commit f727bc9443
4 changed files with 58 additions and 7 deletions

View File

@ -1,3 +1,20 @@
2022-02-04 Jay Berkenbilt <ejb@ql.org>
* 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<T const>. 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 <ejb@ql.org>
* Major refactor: all functionality from the qpdf CLI is now

View File

@ -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<const T> 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<long>(this->data->refcount);
}
T const& operator*() const
{
return *this->data->pointer;

View File

@ -4,8 +4,6 @@
#include <stdlib.h>
#include <list>
#include <qpdf/QUtil.hh>
class Object
{
public:
@ -47,13 +45,20 @@ Object::hello() const
typedef PointerHolder<Object> 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<ObjectHolder> 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<Object const> 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<Object> oarr1_ph(true, new Object[2]);

View File

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