2015-05-24 21:11:36 +00:00
|
|
|
// Copyright (c) 2005-2015 Jay Berkenbilt
|
2008-04-29 12:55:25 +00:00
|
|
|
//
|
|
|
|
// This file is part of qpdf. This software may be distributed under
|
|
|
|
// the terms of version 2 of the Artistic License which may be found
|
|
|
|
// in the source distribution. It is provided "as is" without express
|
|
|
|
// or implied warranty.
|
|
|
|
|
|
|
|
#ifndef __POINTERHOLDER_HH__
|
|
|
|
#define __POINTERHOLDER_HH__
|
|
|
|
|
|
|
|
// This class is basically boost::shared_pointer but predates that by
|
|
|
|
// several years.
|
|
|
|
|
|
|
|
// This class expects to be initialized with a dynamically allocated
|
|
|
|
// object pointer. It keeps a reference count and deletes this once
|
|
|
|
// the reference count goes to zero. PointerHolder objects are
|
|
|
|
// explicitly safe for use in STL containers.
|
|
|
|
|
|
|
|
// It is very important that a client who pulls the pointer out of
|
|
|
|
// this holder does not let the holder go out of scope until it is
|
|
|
|
// finished with the pointer. It is also important that exactly one
|
|
|
|
// instance of this object ever gets initialized with a given pointer.
|
|
|
|
// Otherwise, the pointer will be deleted twice, and before that, some
|
|
|
|
// objects will be left with a pointer to a deleted object. In other
|
|
|
|
// words, the only legitimate way for two PointerHolder objects to
|
|
|
|
// contain the same pointer is for one to be a copy of the other.
|
|
|
|
// Copy and assignment semantics are well-defined and essentially
|
|
|
|
// allow you to use PointerHolder as a means to get pass-by-reference
|
|
|
|
// semantics in a pass-by-value environment without having to worry
|
|
|
|
// about memory management details.
|
|
|
|
|
|
|
|
// Comparison (== and <) are defined and operate on the internally
|
|
|
|
// stored pointers, not on the data. This makes it possible to store
|
|
|
|
// PointerHolder objects in sorted lists or to find them in STL
|
|
|
|
// containers just as one would be able to store pointers. Comparing
|
|
|
|
// the underlying pointers provides a well-defined, if not
|
|
|
|
// particularly meaningful, ordering.
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
class PointerHolder
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
class Data
|
|
|
|
{
|
|
|
|
public:
|
2011-08-11 15:56:37 +00:00
|
|
|
Data(T* pointer, bool array) :
|
2008-04-29 12:55:25 +00:00
|
|
|
pointer(pointer),
|
2011-08-11 15:56:37 +00:00
|
|
|
array(array),
|
2008-04-29 12:55:25 +00:00
|
|
|
refcount(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
~Data()
|
|
|
|
{
|
2011-08-11 15:56:37 +00:00
|
|
|
if (array)
|
2008-04-29 12:55:25 +00:00
|
|
|
{
|
2011-08-11 15:56:37 +00:00
|
|
|
delete [] this->pointer;
|
2008-04-29 12:55:25 +00:00
|
|
|
}
|
2011-08-11 15:56:37 +00:00
|
|
|
else
|
2008-04-29 12:55:25 +00:00
|
|
|
{
|
2011-08-11 15:56:37 +00:00
|
|
|
delete this->pointer;
|
2008-04-29 12:55:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
T* pointer;
|
2011-08-11 15:56:37 +00:00
|
|
|
bool array;
|
2008-04-29 12:55:25 +00:00
|
|
|
int refcount;
|
|
|
|
private:
|
|
|
|
Data(Data const&);
|
|
|
|
Data& operator=(Data const&);
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
2017-08-10 22:17:24 +00:00
|
|
|
PointerHolder(T* pointer = 0)
|
2008-04-29 12:55:25 +00:00
|
|
|
{
|
2011-08-11 15:56:37 +00:00
|
|
|
this->init(new Data(pointer, false));
|
|
|
|
}
|
|
|
|
// Special constructor indicating to free memory with delete []
|
|
|
|
// instead of delete
|
|
|
|
PointerHolder(bool, T* pointer)
|
|
|
|
{
|
|
|
|
this->init(new Data(pointer, true));
|
2008-04-29 12:55:25 +00:00
|
|
|
}
|
|
|
|
PointerHolder(PointerHolder const& rhs)
|
|
|
|
{
|
|
|
|
this->copy(rhs);
|
|
|
|
}
|
|
|
|
PointerHolder& operator=(PointerHolder const& rhs)
|
|
|
|
{
|
|
|
|
if (this != &rhs)
|
|
|
|
{
|
|
|
|
this->destroy();
|
|
|
|
this->copy(rhs);
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
~PointerHolder()
|
|
|
|
{
|
|
|
|
this->destroy();
|
|
|
|
}
|
|
|
|
bool operator==(PointerHolder const& rhs) const
|
|
|
|
{
|
|
|
|
return this->data->pointer == rhs.data->pointer;
|
|
|
|
}
|
|
|
|
bool operator<(PointerHolder const& rhs) const
|
|
|
|
{
|
|
|
|
return this->data->pointer < rhs.data->pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: The pointer returned by getPointer turns into a pumpkin
|
|
|
|
// when the last PointerHolder that contains it disappears.
|
|
|
|
T* getPointer()
|
|
|
|
{
|
|
|
|
return this->data->pointer;
|
|
|
|
}
|
|
|
|
T const* getPointer() const
|
|
|
|
{
|
|
|
|
return this->data->pointer;
|
|
|
|
}
|
|
|
|
int getRefcount() const
|
|
|
|
{
|
|
|
|
return this->data->refcount;
|
|
|
|
}
|
|
|
|
|
2010-09-24 19:09:22 +00:00
|
|
|
T const& operator*() const
|
|
|
|
{
|
|
|
|
return *this->data->pointer;
|
|
|
|
}
|
|
|
|
T& operator*()
|
|
|
|
{
|
|
|
|
return *this->data->pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
T const* operator->() const
|
|
|
|
{
|
|
|
|
return this->data->pointer;
|
|
|
|
}
|
|
|
|
T* operator->()
|
|
|
|
{
|
|
|
|
return this->data->pointer;
|
|
|
|
}
|
|
|
|
|
2008-04-29 12:55:25 +00:00
|
|
|
private:
|
|
|
|
void init(Data* data)
|
|
|
|
{
|
|
|
|
this->data = data;
|
|
|
|
{
|
|
|
|
++this->data->refcount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void copy(PointerHolder const& rhs)
|
|
|
|
{
|
|
|
|
this->init(rhs.data);
|
|
|
|
}
|
|
|
|
void destroy()
|
|
|
|
{
|
|
|
|
bool gone = false;
|
|
|
|
{
|
|
|
|
if (--this->data->refcount == 0)
|
|
|
|
{
|
|
|
|
gone = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (gone)
|
|
|
|
{
|
|
|
|
delete this->data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Data* data;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // __POINTERHOLDER_HH__
|