boost::shared_ptr pimpl and Qt
Posted on 2009-04-22
I recently adopted the pimpl idiom in my code as a clean way of ensuring appropriate behavior and destruction and encapsulation of the shared_ptrs I was passing around previously. I've been implementing it as a boost::shared_ptr to a forward-declared "-Impl" class defined as a struct in the .cpp file.
What I've found, however, is that Qt doesn't like the idea of shared state across objects much at all. I have found a consistent need to create QLists and QMaps of objects that extend QObject, and I had become tired of the extra typing required in making everything a list of MyObject* or shared_ptr<MyObject>, so I had hoped pimpl would resolve this difficulty. As it turns out, connected Qt signals only work on the original object, not its copy, so I had to implement assignment operators and copy constructors to ensure the signals connected in the constructor stayed connected. This has the unfortunate side effect of allowing an object to be copied AFTER signals are assigned externally, and the object has no way of knowing dynamically what it needs to reassign.
It gets worse when multiple threads are involved. If an object creates a background thread for itself during construction, it passes a boost binding to "this" for the thread to call, then after construction it gets copied and destructed, and the "this" reference the thread has is no longer valid. I got around this by passing the pimpl to the thread instead, and modifying the "parent" object of the pimpl during copy and assignment.
Now my code at least works, but in all reality it's no more than an auto_ptr in shared_ptr's clothing, with none of the type safety.
Is there an obvious solution to this? Can Qt support shared pimpls, or is it a lost cause? Do I need to go back to shared_ptrs if I need shared objects?