diff options
author | Thiago Macieira <thiago.macieira@nokia.com> | 2009-07-24 20:39:55 (GMT) |
---|---|---|
committer | Thiago Macieira <thiago.macieira@nokia.com> | 2009-07-24 20:39:55 (GMT) |
commit | b7c29570b9f6fecb6f042532f81e100a1f9b99a9 (patch) | |
tree | 4f2c158af3df6cdf9f7fd1db8ddceb30dbdd2bba /src | |
parent | dffbcfb0adcad91f959a47edfdb5dd623c803306 (diff) | |
download | Qt-b7c29570b9f6fecb6f042532f81e100a1f9b99a9.zip Qt-b7c29570b9f6fecb6f042532f81e100a1f9b99a9.tar.gz Qt-b7c29570b9f6fecb6f042532f81e100a1f9b99a9.tar.bz2 |
Implement a new custom deleter implementation for QSharedPointer
Instead of using a template class derived from
QtSharedPointer::ExternalRefCountData, use a non-template class that
has a function pointer. This avoids generating a virtual table for
each QSharedPointer type and custom deleter.
The trick here is that we don't "new" the d pointer anymore, but we
simply allocate memory (via ::operator new, so it may throw an
exception), then we use the placement new to initialise the
non-template d-pointer and the template deleter sub-objects. Then we
store the pointer to a regular function which will execute the user's
custom deleter.
I also added operator delete() to the class to make sure no smarty
compiler decides to delete the d-pointer with a fixed size (I don't
think that happens, but just to be on the safe side).
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/tools/qsharedpointer_impl.h | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 739a949..706c6ab 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -189,6 +189,59 @@ namespace QtSharedPointer { inline bool destroy() { executeDeleter(ptr, deleter); return true; } }; + template <class T, typename Deleter> + struct CustomDeleter + { + Deleter deleter; + T *ptr; + + inline CustomDeleter(T *p, Deleter d) : deleter(d), ptr(p) {} + }; + + struct ExternalRefCountWithDestroyFn: public ExternalRefCountData + { + typedef void (*DestroyerFn)(ExternalRefCountData *); + DestroyerFn destroyer; + + inline ExternalRefCountWithDestroyFn(DestroyerFn d) + : destroyer(d) + { } + + inline bool destroy() { destroyer(this); return true; } + inline void operator delete(void *ptr) { ::operator delete(ptr); } + }; + + template <class T, typename Deleter> + struct ExternalRefCountWithCustomDeleter: public ExternalRefCountWithDestroyFn + { + typedef ExternalRefCountWithCustomDeleter Self; + typedef ExternalRefCountWithDestroyFn Parent; + typedef CustomDeleter<T, Deleter> Next; + Next extra; + + static inline void deleter(ExternalRefCountData *self) + { + Self *realself = static_cast<Self *>(self); + executeDeleter(realself->extra.ptr, realself->extra.deleter); + } + + static inline Self *create(T *ptr, Deleter userDeleter) + { + DestroyerFn destroy = &deleter; + Self *d = static_cast<Self *>(::operator new(sizeof(Self))); + + // initialize the two sub-objects + new (&d->extra) Next(ptr, userDeleter); + new (d) Parent(destroy); // can't throw + + return d; + } + private: + // prevent construction and the emission of virtual symbols + ExternalRefCountWithCustomDeleter(); + ~ExternalRefCountWithCustomDeleter(); + }; + template <class T> class ExternalRefCount: public Basic<T> { @@ -217,7 +270,7 @@ namespace QtSharedPointer { Basic<T>::internalConstruct(ptr); Q_ASSERT(!d); if (ptr) - d = new ExternalRefCountWithSpecializedDeleter<T, Deleter>(ptr, deleter); + d = ExternalRefCountWithCustomDeleter<T, Deleter>::create(ptr, deleter); } inline ExternalRefCount() : d(0) { } |