[Qt-interest] How to "snapshot" a QObject if it can't be copied?

Hostile Fork hostilefork at gmail.com
Fri Oct 16 08:49:46 CEST 2009


Hi all...

I have a QObject-derived class.  It has signals and slots that modify  
the object's data in a multithreaded environment.  (Yeah, yeah, who  
doesn't?)  :)

I'd like to be able to snapshot that object.  Because certain routines  
would be harmed by getting different answers from method calls on this  
QObject (if modifications happen on the other thread while they are  
working).  So routines have a QObject pointer, they call snapshot(),  
then they make all their method calls on the snapshot.  That way they  
don't see the modifications.

Seems simple in theory.  But here are the rules of my strange game:

	1. I'd like to not pay for the copy unless a modification actually  
happens
	1a. I fixated on the idea that this was an application for  
QSharedDataPointer
	2. This is a property I want enforced on a whole inheritance hierarchy

First barrier is of course that you can't apply copy-on-write to  
QObject, because they can't be copied!  So to make a "copy-on-write"  
QObject, you have to start by giving it a member variable for the  
"state".  You copy the state, not the QObject.  AmIRight?

Second barrier is that I'd like the copy-on-write aspect to be  
enforced by the inheritance hierarchy.  e.g. I have a BaseHolder  
class, and I want all objects derived from BaseHolder to have this  
"you can snapshot me!" property returning a properly typed Base.

Qt and templates tend to not mix well, but for simplicity I'll pretend  
they do.  Here's a non-compiling pseudocode of what I was thinking:

	template< class DerivedDataType >
	class Base
	{
		// This is the base class and you make all your data
		// access methods derive from it, they should all
		// be const because if you modify it won't be reflected
		// back to the BaseHolder!

	protected:
		// Note: DerivedDataType should inherit from QSharedData or obey
		// the shared data protocol
		QSharedDataPointer< DerivedDataType > d;

	public:
		Base (unique_ptr< DerivedDataType >&& init)
			d (move(init))
		{
		}

      		Base (const Base &other)
	           : d (other.d)
		{
		}

		~Base()
		{
			// NOT virtual, to reinforce that you are absolutely
			// not supposed to be putting data members in
			// derived classes.  Put them in the DerivedDataType
			// class!  otherwise how will they make it into the
			// snapshot?
		}
	};

	template< class DerivedDataType >
	class BaseHolder : public QObject
	{
		// This is the QObject class and its slots can modify
		// the state.  some methods const and some non-const

	protected:
		Base< DerivedDataType > state;

	public:
		BaseHolder (unique_ptr< DerivedDataType >&& init) :
			Base(move(init))
		{
		}

      		BaseHolder (const Base &other)
	           : d (other.d)
		{
		}

		Base< DerivedDataType > snapshot()
		{
			// returns an object that is semantically equivalent
			// to making a copy of the current state, but which
			// defers the actual act of copying until a write occurs
			return state;
		}

		virtual ~BaseHolder()
		{
			// This is virtual to indicate that it is okay to clean up
			// any events or signals in your derived destructor.
			// There's only one QObject and if you have mutexes
			// or HttpRequests or whatever then that's fine to
			// clean up here.  But remember that clients
			// won't work w/pointers to BaseHolder... just instances
			// of Base... so if something is part of the data interface
			// make it a method on Base which is a function
			// of DerivedDataType
		}
	};

Sort of?

Making matters worse, the code that calls snapshot() is generic...  
e.g. it must be able to make a snapshot without knowing specifically  
which template instance it is dealing with.  This means I need more  
steps in the class heirarchy, and a virtual copy constructor (e.g.  
clone)

	http://www.parashift.com/c%2B%2B-faq-lite/virtual-functions.html#faq-20.8

This is breaking my brain.  :)  Besides switching from Qt & C++ to a  
language where this can be more naturally expressed, can any sharp  
sticks on qt-interest point me in a good direction or give some  
perspective, given my intention?

Best,
Brian

---
http://hostilefork.com



More information about the Qt-interest-old mailing list