Implicit sharing and mutable members
How do you handle mutable attributes in a class that implements implicit sharing?
A case in point: I have a class that represents a text entry. It allows properties to be set that define how the text looks, and offers a paint method to paint the text using a painter provided as a parameter, and a QRectF to paint into.
I use this class a lot, so I implemented implicit sharing. My private data object looks like this:
@class CGLib_TextEntryPrivate : public QSharedData
// Constructors, Destructor omitted in this example
// Just assume they are here and correct.
QString m_Text; QFont m_Font; QColor m_Color; Qt::Alignment m_Alignment; qreal m_Width; QTextOption::WrapMode m_WordWrapMode; mutable QStaticText m_StaticText; // m_StaticText.size() is unreliable // therefore I do my own size calculation mutable QSizeF m_Size; mutable bool m_bStaticTextValid; mutable QTransform m_LastUsedTransform;
The members m_StaticText and following are basically only caching information. I do not want to update them every time a property is changed, but as late as possible, as rarely as possible.
This can lead to situations where I have to update them in a getter. I have the choice of either making the getter non-const (which leads to lots of problems when using the class in a const-correct code environment), or making those "caching" members mutable.
I chose the latter. Can I run into implicit sharing troubles that way?
The main class has, of course, a shared data pointer:
Whenever I change anything that must lead to a cache update, I call an invalidation function, which is non-const:
d->m_bStaticTextValid = false;
In some of the getters, I call an update function which changes only mutable members, and is const:
@QSizeF CGLib_TextEntry::size() const
updateStaticText(); // This is a const function I am calling
I might just as well be fine with the way the class is right now: The caching information can only change after one of the non-mutable members has changed. This change must have already caused the detach to happen, which means I am updating the cache information in an object which is already detached. The question is: Are there any holes in this reasoning?
I don't see any holes, currently. Only the one with detach. changing members implicitly, which might affect other users of the shared object looks not the best.
But it could work.