You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
434 lines
12 KiB
434 lines
12 KiB
/***************************************************************************
|
|
begin : Wed Jan 1 17:56 CET 2003
|
|
copyright : (C) 2003 by Tim Jansen
|
|
email : tim@tjansen.de
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#ifndef SMARTPTR_H
|
|
#define SMARTPTR_H
|
|
|
|
#include <tqstring.h>
|
|
|
|
class WeakPtr;
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
struct SmartPtrRefCount {
|
|
SmartPtrRefCount(int toObj, int toThis) :
|
|
refsToObject(toObj),
|
|
refsToThis(toThis) {
|
|
}
|
|
int refsToObject; // number of pointers to the object, 0 if released
|
|
int refsToThis; // number of pointer to the ref count
|
|
};
|
|
|
|
/**
|
|
* SmartPtr is a reference counting smart pointer. When you create
|
|
* the first instance it will create a new counter for the pointee
|
|
* and it share it with all other SmartPtr instances for that pointee.
|
|
* The reference count can only be kept accurate when you do not create
|
|
* a second 'realm' of references by converting a SmartPtr into a
|
|
* regular pointer and then create a new SmartPtr from that pointer.
|
|
* When the last instance of a SmartPtr for the given object has been
|
|
* deleted the object itself will be deleted. You can stop the SmartPtr
|
|
* system to manage an object by calling @ref release() on any of
|
|
* the pointers pointing to that object. All SmartPtrs will then stop
|
|
* managing the object, and you can also safely create a second 'realm'.
|
|
*
|
|
* SmartPtr can be combined with @ref WeakPtr. A WeakPtr
|
|
* does not influence its life cycle, but notices when a SmartPtr
|
|
* deletes the object.
|
|
*
|
|
* The recommended way to use SmartPtr and @ref WeakPtr is to use SmartPtr
|
|
* for all aggregations and WeakPtr for associations. Unlike auto_ptr,
|
|
* SmartPtr can be used in collections.
|
|
*
|
|
* SmartPtr is not thread-safe. All instances of SmartPtrs pointing
|
|
* to a pointee must always be in the same thread, unless you break
|
|
* the 'realm' by calling @ref release() in one thread and give the
|
|
* original pointer the other thread. It can then create a new SmartPtr
|
|
* and control the lifecycle of the object.
|
|
* @see WeakPtr
|
|
*/
|
|
template <class T>
|
|
class SmartPtr
|
|
{
|
|
public: // members are public because of problems with gcc 3.2
|
|
friend class WeakPtr;
|
|
|
|
/// @internal
|
|
T* ptr;
|
|
/// @internal
|
|
mutable SmartPtrRefCount *rc; // if !rc, refcount=1 is assumed
|
|
|
|
protected:
|
|
void freePtr() {
|
|
if (!ptr)
|
|
return;
|
|
if (!rc)
|
|
delete ptr;
|
|
else {
|
|
if (rc->refsToObject > 0) {
|
|
Q_ASSERT(rc->refsToObject >= rc->refsToThis);
|
|
if (rc->refsToObject == 1) {
|
|
delete ptr;
|
|
rc->refsToObject = -1;
|
|
}
|
|
else
|
|
rc->refsToObject--;
|
|
}
|
|
rc->refsToThis--;
|
|
if (rc->refsToThis < 1)
|
|
delete rc;
|
|
}
|
|
}
|
|
|
|
void init(T *sptr, SmartPtrRefCount *&orc)
|
|
{
|
|
ptr = sptr;
|
|
if (!sptr)
|
|
rc = 0;
|
|
else if (!orc) {
|
|
orc = new SmartPtrRefCount(2, 2);
|
|
rc = orc;
|
|
}
|
|
else {
|
|
rc = orc;
|
|
rc->refsToThis++;
|
|
if (rc->refsToObject) {
|
|
// prevent initialization from invalid WeakPtr
|
|
Q_ASSERT(rc->refsToObject > 0);
|
|
rc->refsToObject++;
|
|
}
|
|
}
|
|
}
|
|
|
|
SmartPtr(T *p, SmartPtrRefCount *&orc)
|
|
{
|
|
init(p, orc);
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* Creates a SmartPtr that refers to the given pointer @p.
|
|
* SmartPtr will take control over the object and delete it
|
|
* when the last SmartPtr that referes to the object
|
|
* has been deleted.
|
|
* @param p the pointer to the object to manage, or the null pointer
|
|
*/
|
|
SmartPtr(T* p = 0) :
|
|
ptr(p),
|
|
rc(0)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Copies the given SmartPtr, sharing ownership with the other
|
|
* pointer. Increases the reference count by 1 (if the object
|
|
* has not been @ref release()d).
|
|
* @param sptr the object pointer to copy
|
|
*/
|
|
SmartPtr(const SmartPtr<T> &sptr)
|
|
{
|
|
init(sptr.ptr, sptr.rc);
|
|
}
|
|
|
|
/**
|
|
* Copies the given SmartPtr, sharing ownership with the other
|
|
* pointer. Increases the reference count by 1 (if the object
|
|
* has not been @ref release()d).
|
|
* @param sptr the object pointer to copy
|
|
*/
|
|
template<class T2>
|
|
SmartPtr(const SmartPtr<T2> &sptr)
|
|
{
|
|
init((T*)sptr.ptr, sptr.rc);
|
|
}
|
|
|
|
/**
|
|
* Delete the pointer and, if the reference count is one and the object has not
|
|
* been released, deletes the object.
|
|
*/
|
|
~SmartPtr() {
|
|
freePtr();
|
|
}
|
|
|
|
/**
|
|
* Copies the given SmartPtr, sharing ownership with the other
|
|
* pointer. Increases the reference count by 1 (if the object
|
|
* has not been @ref release()d). The original object will be dereferenced
|
|
* and thus deleted, if the reference count is 1.
|
|
* @param sptr the object pointer to copy
|
|
* @return this SmartPtr object
|
|
*/
|
|
SmartPtr &operator=(const SmartPtr<T> &sptr) {
|
|
if (this == &sptr)
|
|
return *this;
|
|
|
|
freePtr();
|
|
init(sptr.ptr, sptr.rc);
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Copies the given SmartPtr, sharing ownership with the other
|
|
* pointer. Increases the reference count by 1 (if the object
|
|
* has not been @ref release()d). The original object will be dereferenced
|
|
* and thus deleted, if the reference count is 1.
|
|
* @param sptr the object pointer to copy
|
|
* @return this SmartPtr object
|
|
*/
|
|
template<class T2>
|
|
SmartPtr &operator=(const SmartPtr<T2> &sptr) {
|
|
if (this == static_cast<SmartPtr<T> >(&sptr))
|
|
return *this;
|
|
|
|
freePtr();
|
|
init(static_cast<T>(sptr.ptr), sptr.rc);
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Sets the SmartPointer to the given value. The original object
|
|
* will be dereferenced and thus deleted, if the reference count is 1.
|
|
* @param p the value of the new pointer
|
|
*/
|
|
void set(T *p) {
|
|
if (ptr == p)
|
|
return;
|
|
freePtr();
|
|
|
|
ptr = p;
|
|
rc = 0;
|
|
}
|
|
|
|
/**
|
|
* Releases the ptr. This means it will not be memory-managed
|
|
* anymore, neither by this SmartPtr nor by any other pointer that
|
|
* shares the object. The caller is responsible for freeing the
|
|
* object. It is possible to assign the plain pointer (but not the
|
|
* SmartPtr!) to another SmartPtr that will then start memory
|
|
* management. This may be useful, for example, to let another
|
|
* thread manage the lifecyle.
|
|
* @return the pointer, must be freed by the user
|
|
* @see data()
|
|
*/
|
|
T* release() {
|
|
if (!rc)
|
|
rc = new SmartPtrRefCount(0, 1);
|
|
else
|
|
rc->refsToObject = 0;
|
|
return ptr;
|
|
}
|
|
|
|
/**
|
|
* Sets the SmartPointer to the given value. The original object
|
|
* will be dereferenced and thus deleted, if the reference count is 1.
|
|
* @param p the value of the new pointer
|
|
* @return this SmartPtr object
|
|
*/
|
|
SmartPtr &operator=(T *p) {
|
|
set(p);
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the SmartPtr points to an actual object, false
|
|
* if it is the null pointer.
|
|
* @return true for an actual pointer, false for the null pointer
|
|
*/
|
|
operator bool() const {
|
|
return ptr != 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the plain pointer to the pointed object. The object will
|
|
* still be managed by the SmartPtr. You must ensure that the pointer
|
|
* is valid (so don't delete the SmartPtr before you are done with the
|
|
* plain pointer).
|
|
* @return the plain pointer
|
|
* @see data()
|
|
* @see release()
|
|
* @see WeakPtr
|
|
*/
|
|
template<class T2>
|
|
operator T2*() const {
|
|
return static_cast<T2*>(ptr);
|
|
}
|
|
|
|
/**
|
|
* Returns the plain pointer to the pointed object. The object will
|
|
* still be managed by the SmartPtr. You must ensure that the pointer
|
|
* is valid (so don't delete the SmartPtr before you are done with the
|
|
* plain pointer).
|
|
* @return the plain pointer
|
|
* @see data()
|
|
* @see release()
|
|
* @see WeakPtr
|
|
*/
|
|
template<class T2>
|
|
operator const T2*() const {
|
|
return static_cast<const T2*>(ptr);
|
|
}
|
|
|
|
/**
|
|
* Returns a reference to the pointed object. This works exactly
|
|
* like on a regular pointer.
|
|
* @return the pointer object
|
|
*/
|
|
T& operator*() {
|
|
return *ptr;
|
|
}
|
|
|
|
/**
|
|
* Returns a reference to the pointed object. This works exactly
|
|
* like on a regular pointer.
|
|
* @return the pointer object
|
|
*/
|
|
const T& operator*() const {
|
|
return *ptr;
|
|
}
|
|
|
|
/**
|
|
* Access a member of the pointed object. This works exactly
|
|
* like on a regular pointer.
|
|
* @return the pointer
|
|
*/
|
|
T* operator->() {
|
|
return ptr;
|
|
}
|
|
|
|
/**
|
|
* Access a member of the pointed object. This works exactly
|
|
* like on a regular pointer.
|
|
* @return the pointer
|
|
*/
|
|
const T* operator->() const {
|
|
return ptr;
|
|
}
|
|
|
|
/**
|
|
* Compares two SmartPtrs. They are equal if both point to the
|
|
* same object.
|
|
* @return true if both point to the same object
|
|
*/
|
|
bool operator==(const SmartPtr<T>& sptr) const {
|
|
return ptr == sptr.ptr;
|
|
}
|
|
|
|
/**
|
|
* Compares two SmartPtrs. They are unequal if both point to
|
|
* different objects.
|
|
* @return true if both point to different objects
|
|
*/
|
|
bool operator!=(const SmartPtr<T>& sptr) const {
|
|
return ptr != sptr.ptr;
|
|
}
|
|
|
|
/**
|
|
* Compares a SmartPtr with a plain pointer. They are equal if
|
|
* both point to the same object.
|
|
* @return true if both point to the same object
|
|
*/
|
|
bool operator==(const T* p) const {
|
|
return ptr == p;
|
|
}
|
|
|
|
/**
|
|
* Compares a SmartPtr with a plain pointer. They are unequal if
|
|
* both point to different objects.
|
|
* @return true if both point to different objects
|
|
*/
|
|
bool operator!=(const T* p) const {
|
|
return ptr != p;
|
|
}
|
|
|
|
/**
|
|
* Negates the pointer. True if the pointer is the null pointer
|
|
* @return true for the null pointer, false otherwise
|
|
*/
|
|
bool operator!() const {
|
|
return ptr == 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the pointer. The object will still be managed
|
|
* by the SmartPtr. You must ensure that the pointer
|
|
* is valid (so don't delete the SmartPtr before you are done with the
|
|
* plain pointer).
|
|
* @return the plain pointer
|
|
* @see release()
|
|
* @see WeakPtr
|
|
*/
|
|
T* data() {
|
|
return ptr;
|
|
}
|
|
|
|
/**
|
|
* Returns the pointer. The object will still be managed
|
|
* by the SmartPtr. You must ensure that the pointer
|
|
* is valid (so don't delete the SmartPtr before you are done with the
|
|
* plain pointer).
|
|
* @return the plain pointer
|
|
* @see release()
|
|
* @see WeakPtr
|
|
*/
|
|
const T* data() const {
|
|
return ptr;
|
|
}
|
|
|
|
/**
|
|
* Checks whether both SmartPtrs use the same pointer but two
|
|
* different reference counts.
|
|
* If yes, one of them must be 0 (object released), otherwise
|
|
* it is an error.
|
|
* @return true if the pointers are used correctly
|
|
*/
|
|
bool isRCCorrect(const SmartPtr<T> &p2) const {
|
|
if (ptr == p2.ptr)
|
|
return true;
|
|
if (rc == p2.rc)
|
|
return true;
|
|
return (rc->refsToObject == 0) || (p2.rc->refsToObject == 0);
|
|
}
|
|
|
|
/**
|
|
* Returns the reference count of the object. The count is 0 if
|
|
* the object has been released (@ref release()). For the null pointer
|
|
* the reference count is always 1.
|
|
* @return the reference count, or 0 for released objects
|
|
*/
|
|
int referenceCount() const {
|
|
return rc ? rc->refsToObject : 1;
|
|
}
|
|
|
|
/**
|
|
* Returns a string representation of the pointer.
|
|
* @return a string representation
|
|
*/
|
|
TQString toString() const {
|
|
int objrcount = 1;
|
|
int rcrcount = 0;
|
|
|
|
if (rc) {
|
|
objrcount = rc->refsToObject;
|
|
rcrcount = rc->refsToThis;
|
|
}
|
|
return TQString("SmartPtr: ptr=%1, refcounts=%2, ptrnum=%3")
|
|
.arg((int)ptr).arg(objrcount).arg(rcrcount);
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|