summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@nokia.com>2009-07-24 20:39:55 (GMT)
committerThiago Macieira <thiago.macieira@nokia.com>2009-07-24 20:39:55 (GMT)
commitb7c29570b9f6fecb6f042532f81e100a1f9b99a9 (patch)
tree4f2c158af3df6cdf9f7fd1db8ddceb30dbdd2bba /src
parentdffbcfb0adcad91f959a47edfdb5dd623c803306 (diff)
downloadQt-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.h55
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) { }